Plus longue sous-séquence commune

Page d’aide sur l’homonymie

Ne doit pas être confondu avec plus longue sous-chaîne commune.

En informatique théorique, la plus longue sous-séquence commune à deux suites, ou deux chaînes de caractères, est une sous-suite extraite des deux suites, et de taille maximum. La résolution de ce problème peut être obtenue par programmation dynamique.

La généralisation à un nombre arbitraire de suites est un problème NP-difficile[1] : le temps d'exécution de tout algorithme est exponentiel en le nombre de séquences.

Exemple

Pour les deux séquences de caractères suivantes :

  • « abcde »,
  • « ceij »,

la plus longue sous-séquence commune est « ce ».

Dans ce problème, il est nécessaire que les éléments communs soient dans le même ordre dans les différentes séquences, mais pas qu’ils soient obligatoirement consécutifs : « e » n’est pas consécutif à « c » dans la première séquence.

Algorithme par force brute

On constate par dénombrement qu'il existe 2 n {\displaystyle 2^{n}} sous-séquences pour une chaîne de longueur n {\displaystyle n} . Les essayer toutes par force brute pour trouver la plus longue qui soit une sous-séquence d'une autre chaîne a donc une complexité exponentielle, ce qui n'est pas souhaitable en pratique.

Résolution en temps polynomial pour deux suites

Une telle sous-séquence peut être obtenue par un algorithme de programmation dynamique dont le temps d'exécution est proportionnel au produit des longueurs des deux séquences[2].

Structure d'une solution

Il est possible de ramener le problème de recherche de plus longue sous séquence commune (PLSC) entre deux chaînes données à une recherche entre deux chaînes de taille inférieure grâce au théorème suivant (où X l {\displaystyle X_{l}} désigne les l {\displaystyle l} premiers caractères de la séquence X {\displaystyle X} )[2]:

Théorème — Soit X = [ x 1 , , x m ] {\displaystyle X=[x_{1},\dots ,x_{m}]} et Y = [ y 1 , , y n ] {\displaystyle Y=[y_{1},\dots ,y_{n}]} deux séquences, et soit Z = [ z 1 , , z k ] {\displaystyle Z=[z_{1},\dots ,z_{k}]} une plus longue sous-séquence commune quelconque de X {\displaystyle X} et Y {\displaystyle Y} . On a alors :

  • Si x m = y n {\displaystyle x_{m}=y_{n}} alors z k = x m = y n {\displaystyle z_{k}=x_{m}=y_{n}} et de plus Z k 1 {\displaystyle Z_{k-1}} est une PLSC de X m 1 {\displaystyle X_{m-1}} et Y n 1 {\displaystyle Y_{n-1}}  ;
  • Si x m y n {\displaystyle x_{m}\neq y_{n}} alors si z k x m {\displaystyle z_{k}\neq x_{m}} on a Z {\displaystyle Z} qui est une PLSC de X m 1 {\displaystyle X_{m-1}} et Y {\displaystyle Y}  ;
  • Si x m y n {\displaystyle x_{m}\neq y_{n}} alors si z k y n {\displaystyle z_{k}\neq y_{n}} on a Z {\displaystyle Z} qui est une PLSC de X {\displaystyle X} et Y n 1 {\displaystyle Y_{n-1}} .

Les trois cas x m = y n {\displaystyle \left\langle x_{m}=y_{n}\right\rangle } , x m y n   E T   z k x m {\displaystyle \left\langle x_{m}\neq y_{n}~{\mathsf {ET}}~z_{k}\neq x_{m}\right\rangle } et x m y n   E T   z k y n {\displaystyle \left\langle x_{m}\neq y_{n}~{\mathsf {ET}}~z_{k}\neq y_{n}\right\rangle } sont exhaustifs, ce qui permet bien de se ramener à un problème de taille inférieure.

Longueur des plus longues sous-séquences communes

On crée un tableau à deux dimensions c [ 1 m ] [ 1 n ] {\displaystyle c[1\cdot \cdot m][1\cdot \cdot n]} dans lequel chaque case c [ i ] [ j ] {\displaystyle c[i][j]} est destiné à contenir la longueur des PLSCs entre X i {\displaystyle X_{i}} et Y j {\displaystyle Y_{j}} . On peut alors calculer de proche en proche c [ i ] [ j ] {\displaystyle c[i][j]} pour chaque couple d'indice i {\displaystyle i} et j {\displaystyle j} . Du théorème précédent découle en effet la formule[2]:

c [ i ] [ j ] = { 0  si  i = 0  ou  j = 0 , c [ i 1 ] [ j 1 ] + 1  si  i , j > 0  et  x i = y j , m a x ( c [ i ] [ j 1 ] , c [ i 1 ] [ j ] )  si  i , j > 0  et  x i y j . {\displaystyle c[i][j]={\begin{cases}0&{\text{ si }}i=0{\text{ ou }}j=0,\\c[i-1][j-1]+1&{\text{ si }}i,j>0{\text{ et }}x_{i}=y_{j},\\{\mathsf {max}}(c[i][j-1],c[i-1][j])&{\text{ si }}i,j>0{\text{ et }}x_{i}\neq y_{j}.\end{cases}}}

Le calcul du contenu des cases de c {\displaystyle c} peut être effectué avec une complexité O ( m n ) {\displaystyle {\mathcal {O}}(mn)} , car le contenu de chaque case est calculable à partir des cases précédente en O ( 1 ) {\displaystyle {\mathcal {O}}(1)} [2].

Obtention d'une plus longue sous-séquence commune

La formule précédente permet de calculer de proche en proche les cases de c {\displaystyle c} . On peut reconstituer une plus longue sous-séquence commune grâce à lui.

Pour cela on effectue un parcours depuis c [ m ] [ n ] {\displaystyle c[m][n]} suivant la règle suivante

Depuis une case c [ i ] [ j ] {\displaystyle c[i][j]} de valeur α {\displaystyle \alpha } :

  • Si x i = y j {\displaystyle x_{i}=y_{j}} , on passe à la case c [ i 1 ] [ j 1 ] {\displaystyle c[i-1][j-1]} de valeur α 1 {\displaystyle \alpha -1} et on ajoute ce caractère ( x i = y j {\displaystyle x_{i}=y_{j}} ) au début de la PLSC en construction.
  • Si x i y j {\displaystyle x_{i}\neq y_{j}} ,
    • Si c [ i ] [ j 1 ] = c [ i 1 ] [ j ] = α {\displaystyle c[i][j-1]=c[i-1][j]=\alpha } , on passe indifféremment à la case c [ i 1 ] [ j ] {\displaystyle c[i-1][j]} ou c [ i ] [ j 1 ] {\displaystyle c[i][j-1]} .
    • Si c [ i ] [ j 1 ] = α > c [ i 1 ] [ j ] {\displaystyle c[i][j-1]=\alpha >c[i-1][j]} , on passe à la case c [ i ] [ j 1 ] {\displaystyle c[i][j-1]}
    • Si c [ i 1 ] [ j ] = α > c [ i ] [ j 1 ] {\displaystyle c[i-1][j]=\alpha >c[i][j-1]} , on passe à la case c [ i 1 ] [ j ] {\displaystyle c[i-1][j]}

Un exemple de parcours est donné par le tableau suivant, grâce auquel on déduit que MJAU est une plus longue sous-séquence commune à MZJAWXU et XMJYAUZ :

0 1 2 3 4 5 6 7
Ø M Z J A W X U
0 Ø 0 0 0 0 0 0 0 0
1 X 0 0 0 0 0 0 1 1
2 M 0 1 1 1 1 1 1 1
3 J 0 1 1 2 2 2 2 2
4 Y 0 1 1 2 2 2 2 2
5 A 0 1 1 2 3 3 3 3
6 U 0 1 1 2 3 3 3 4
7 Z 0 1 2 2 3 3 3 4

Complexité de l'algorithme

Le calcul du contenu des cases de c {\displaystyle c} peut être effectué avec une complexité O ( m n ) {\displaystyle {\mathcal {O}}(mn)} , car le contenu de chaque case est calculable à partir des cases précédente en O ( 1 ) {\displaystyle {\mathcal {O}}(1)} [2].

Une fois c {\displaystyle c} connu, l'obtention d'une PLSC a une complexité O ( m + n ) {\displaystyle {\mathcal {O}}(m+n)} [2].

Notes et références

  1. David Maier, « The Complexity of Some Problems on Subsequences and Supersequences », Journal of the ACM, vol. 25, no 2,‎ , p. 322-336 (DOI 10.1145/322063.322075 Accès libre, S2CID 16120634)
  2. a b c d e et f Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest et Clifford Stein, Introduction à l'algorithmique, Dunod, [détail de l’édition], chapitre 15.4, Programmation dynamique : plus longue sous-séquence commune.

Bibliographie complémentaire

  • Masashi Kiyomi, Takashi Horiyama et Yota Otachi, « Longest common subsequence in sublinear space », Information Processing Letters, vol. 168,‎ , article no 106084 (DOI 10.1016/j.ipl.2020.106084)
  • Hideo Bannai, Tomohiro I et Dominik Köppl, « Longest bordered and periodic subsequences », Information Processing Letters, vol. 182,‎ , article no 106398 (DOI 10.1016/j.ipl.2023.106398)

Voir aussi

v · m
Algorithmique du texte
Recherche de sous-chaîne
Alignement de chaînes
Mesure de similarité
Arbre des suffixes
Comparaisons
  • icône décorative Portail de l'informatique théorique