Nejdelší běžný problém s posloupností - Longest common subsequence problem
The nejdelší společná posloupnost (LCS) problém je problém najít nejdelší subsekvence společné pro všechny sekvence v sadě sekvencí (často jen dvě sekvence). Liší se od nejdelší běžný problém s podřetězcem: na rozdíl od podřetězců nejsou subsekvence nutné k obsazení po sobě jdoucích pozic v původních sekvencích. Nejdelší běžný problém s posloupností je klasický počítačová věda problém, základ porovnání dat programy jako rozdíl nástroj a má aplikace v výpočetní lingvistika a bioinformatika. To je také široce používán systémy kontroly revizí jako Git pro usmíření několik změn provedených v kolekci souborů řízených revizemi.
Zvažte například sekvence (ABCD) a (ACBAD). Mají 5 společných subsekvencí délky 2: (AB), (AC), (AD), (BD) a (CD); 2 společné délky a 3 společné subsekvence: (ABD) a (ACD); a již běžné posloupnosti. Takže (ABD) a (ACD) jsou jejich nejdelší společné subsekvence.
Složitost
Problém je v obecném případě libovolného počtu vstupních sekvencí NP-tvrdé.[1] Když je počet sekvencí konstantní, problém je řešitelný v polynomiálním čase pomocí dynamické programování.
Dáno sekvence délek , naivní hledání by otestovalo každou z subsekvence první sekvence k určení, zda jsou také subsekvencemi zbývajících sekvencí; každá subsekvence může být testována v čase lineárně v délkách zbývajících sekvencí, takže čas pro tento algoritmus bude
Pro případ dvou sekvencí n a m prvků, doba běhu přístupu dynamického programování je Ó (n × m).[2] Pro libovolný počet vstupních sekvencí poskytuje řešení dynamický programovací přístup
Existují metody s nižší složitostí,[3]které často závisí na délce LCS, velikosti abecedy nebo na obou.
LCS není nutně jedinečný; v nejhorším případě je počet běžných subsekvencí v délkách vstupů exponenciální, takže algoritmická složitost musí být alespoň exponenciální.[4]
Řešení pro dvě sekvence
Problém LCS má optimální spodní konstrukce: problém lze rozdělit na menší, jednodušší dílčí problémy, které lze následně rozdělit na jednodušší dílčí problémy atd., dokud nakonec nebude řešení triviální. Zejména LCS má překrývající se dílčí problémy: řešení dílčích problémů na vysoké úrovni často znovu používají řešení dílčích problémů na nižší úrovni. Problémy s těmito dvěma vlastnostmi lze vyřešit dynamické programování přístupy, ve kterých jsou dílčí řešení memoized, to znamená, že řešení dílčích problémů jsou uložena pro opětovné použití.
Předpony
Předpona Sn z S je definován jako první n znaky S.[5] Například předpony S = (AGCA) jsou
- S0 = ()
- S1 = (A)
- S2 = (AG)
- S3 = (AGC)
- S4 = (AGCA).
Definujte funkci LCS(X, Y) jako nejdelší společné posloupnosti X a Y. Tato funkce má dvě zajímavé vlastnosti.
První vlastnost
Předpokládejme, že obě sekvence končí ve stejném prvku. Pak je jejich LCS LCS sekvence s vyloučeným posledním prvkem, s připojeným společným posledním prvkem.
Například LCS ((BANANA), (ATANA)) = LCS ((BANAN), (ATAN)) ^ (A), kde ^ označuje zřetězení řetězců. Pokračování pro zbývající společné prvky, LCS ((BANANA), (ATANA)) = LCS ((BAN), (AT)) ^ (ANA).
Obecně platí, že pro jakékoli sekvence X a Y délky n a m, pokud označíme jejich prvky X1 na Xn a y1 na ym a jejich předpony X1 na Xn-1 a Y1 na Ym-1, pak:
- Li: Xn=ym
- pak: LCS(Xn, Ym) = LCS( Xn-1, Ym-1) ^ Xn. Všimněte si, že LCS pro Xn a Ym zahrnuje stanovení LCS kratších sekvencí, Xn-1 a Ym-1.
Druhá vlastnost
Předpokládejme, že dvě sekvence X a Y nekončí stejným symbolem. LCS X a Y je tedy delší LCS (Xn, Ym-1) a LCS (Xn-1, Ym).
Chcete-li porozumět této vlastnosti, zvažte dvě následující sekvence:
posloupnost X: (ABCDEFG) (n prvků)
posloupnost Y: (BCDGK) (m prvků)
LCS těchto dvou sekvencí končí buď G (poslední prvek sekvence X), nebo nekončí.
Případ 1: LCS končí písmenem G
Pak to nemůže skončit K. Takže to neuškodí odstranit K ze sekvence Y: pokud by K byly v LCS, byl by to jeho poslední znak; v důsledku toho K není v LCS. Takže LCS (Xn, Ym) = LCS (Xn, Ym-1).
Případ 2: LCS nekončí písmenem G
Poté můžeme odstranit G ze sekvence X (ze stejného důvodu jako výše). Takže LCS (Xn, Ym) = LCS (Xn-1, Ym).
LCS, který hledáme, je v každém případě jedním z LCS (Xn, Ym-1) nebo LCS (Xn-1, Ym). Tyto dvě poslední LCS jsou obě společné subsekvence X a Y. LCS (X, Y) je nejdelší. Jeho hodnota je tedy nejdelší sekvencí LCS (Xn, Ym-1) a LCS (Xn-1, Ym).
LCS funkce definována
Nechť jsou dvě sekvence definovány takto: a . Předpony jsou ; předpony jsou . Nechat představují množinu nejdelší společné posloupnosti předpon a . Tato sada sekvencí je dána následujícím textem.
Chcete-li najít LCS a , porovnat a . Pokud jsou stejné, pak sekvence je rozšířen o tento prvek, . Pokud nejsou stejné, pak delší ze dvou sekvencí, , a , je zachován. (Pokud mají stejnou délku, ale nejsou totožné, zůstanou obě zachovány.)
Pracoval příklad
Nejdelší společná posloupnost R = (GAC) a C = (AGCAT) bude nalezen. Protože LCS funkce používá prvek „nula“, je vhodné definovat nulové předpony, které jsou pro tyto sekvence prázdné: R0 = Ø; a C0 = Ø. Všechny předpony jsou umístěny v tabulce s C v první řadě (což je Czáhlaví sloupce) a R v prvním sloupci (což je a row header).
Ó | A | G | C | A | T | |
---|---|---|---|---|---|---|
Ó | Ó | Ó | Ó | Ó | Ó | Ó |
G | Ó | |||||
A | Ó | |||||
C | Ó |
Tato tabulka slouží k uložení sekvence LCS pro každý krok výpočtu. Druhý sloupec a druhý řádek byly vyplněny s Ø, protože při porovnání prázdné sekvence s neprázdnou sekvencí je nejdelší společnou posloupností vždy prázdná sekvence.
LCS(R1, C1) je určen porovnáním prvních prvků v každé sekvenci. G a A nejsou stejné, takže tento LCS získá (pomocí „druhé vlastnosti“) nejdelší ze dvou sekvencí, LCS(R1, C0) a LCS(R0, C1). Podle tabulky jsou oba prázdné, takže LCS(R1, C1) je také prázdný, jak ukazuje následující tabulka. Šipky označují, že sekvence pochází z obou buněk výše, LCS(R0, C1) a buňka vlevo, LCS(R1, C0).
LCS(R1, C2) je určeno porovnáním G a G. Shodují se, takže G je připojeno k levé horní posloupnosti, LCS(R0, C1), což je (Ø), což dává (ØG), což je (G).
Pro LCS(R1, C3), G a C se neshodují. Sekvence výše je prázdná; ten nalevo obsahuje jeden prvek, G. Vyberte nejdelší z nich, LCS(R1, C3) je (G). Šipka ukazuje doleva, protože to je nejdelší ze dvou sekvencí.
LCS(R1, C4), podobně, je (G).
LCS(R1, C5), je také (G).
Ó | A | G | C | A | T | |
---|---|---|---|---|---|---|
Ó | Ó | Ó | Ó | Ó | Ó | Ó |
G | Ó | Ó | (G) | (G) | (G) | (G) |
A | Ó | |||||
C | Ó |
Pro LCS(R2, C1), A se porovnává s A. Dva prvky se shodují, takže A je připojeno k Ø, což dává (A).
Pro LCS(R2, C2), A a G se neshodují, takže nejdelší z LCS(R1, C2), což je (G) a LCS(R2, C1), což je (A), se používá. V tomto případě každý obsahuje jeden prvek, takže tomuto LCS jsou dány dvě subsekvence: (A) a (G).
Pro LCS(R2, C3), A neodpovídá C. LCS(R2, C2) obsahuje sekvence (A) a (G); LCS (R1, C3) je (G), který je již obsažen v LCS(R2, C2). Výsledkem je to LCS(R2, C3) obsahuje také dvě subsekvence, (A) a (G).
Pro LCS(R2, C4), A odpovídá A, který je připojen k levé horní buňce, což dává (GA).
Pro LCS(R2, C5), A neodpovídá T. Ve srovnání se dvěma sekvencemi (GA) a (G) je nejdelší (GA), takže LCS(R2, C5) je (GA).
Ó | A | G | C | A | T | |
---|---|---|---|---|---|---|
Ó | Ó | Ó | Ó | Ó | Ó | Ó |
G | Ó | Ó | (G) | (G) | (G) | (G) |
A | Ó | (A) | (A) a (G) | (A) a (G) | (GA) | (GA) |
C | Ó |
Pro LCS(R3, C1), C a A se neshodují, takže LCS(R3, C1) získá nejdelší ze dvou sekvencí (A).
Pro LCS(R3, C2), C a G se neshodují. Oba LCS(R3, C1) a LCS(R2, C2) mají jeden prvek. Výsledkem je to LCS(R3, C2) obsahuje dvě subsekvence, (A) a (G).
Pro LCS(R3, C3), C a C se shodují, takže C je připojeno LCS(R2, C2), který obsahuje dvě subsekvence (A) a (G), přičemž dává (AC) a (GC).
Pro LCS(R3, C4), C a A se neshodují. Kombinování LCS(R3, C3), který obsahuje (AC) a (GC) a LCS(R2, C4), který obsahuje (GA), poskytuje celkem tři sekvence: (AC), (GC) a (GA).
Konečně pro LCS(R3, C5), C a T se neshodují. Výsledkem je to LCS(R3, C5) obsahuje také tři sekvence (AC), (GC) a (GA).
Ó | A | G | C | A | T | |
---|---|---|---|---|---|---|
Ó | Ó | Ó | Ó | Ó | Ó | Ó |
G | Ó | Ó | (G) | (G) | (G) | (G) |
A | Ó | (A) | (A) a (G) | (A) a (G) | (GA) | (GA) |
C | Ó | (A) | (A) a (G) | (AC) a (GC) | (AC) & (GC) & (GA) | (AC) & (GC) & (GA) |
Konečným výsledkem je, že poslední buňka obsahuje všechny nejdelší subsekvence společné pro (AGCAT) a (GAC); to jsou (AC), (GC) a (GA). Tabulka také zobrazuje nejdelší běžné subsekvence pro každou možnou dvojici předpon. Například pro (AGC) a (GA) jsou nejdelší běžnou subsekvenci (A) a (G).
Traceback přístup
Výpočet LCS řádku tabulky LCS vyžaduje pouze řešení aktuálního řádku a předchozího řádku. Přesto u dlouhých sekvencí mohou být tyto sekvence četné a dlouhé, což vyžaduje hodně úložného prostoru. Úložný prostor lze uložit tak, že neukládáte skutečné podsekvence, ale délku podsekvence a směr šipek, jak je uvedeno v tabulce níže.
Ó | A | G | C | A | T | |
---|---|---|---|---|---|---|
Ó | 0 | 0 | 0 | 0 | 0 | 0 |
G | 0 | 0 | 1 | 1 | 1 | 1 |
A | 0 | 1 | 1 | 1 | 2 | 2 |
C | 0 | 1 | 1 | 2 | 2 | 2 |
Skutečné subsekvence jsou odvozeny v proceduře "zpětného sledování", která následuje šipky zpět, počínaje od poslední buňky v tabulce. Když se délka zmenšuje, musely mít sekvence společný prvek. Pokud jsou v buňce zobrazeny dvě šipky, je možné několik cest. Níže je tabulka pro takovou analýzu s čísly zabarvenými do buněk, kde se délka zmenší. Tučná čísla sledují sekvenci (GA).[6]
Ó | A | G | C | A | T | |
---|---|---|---|---|---|---|
Ó | 0 | 0 | 0 | 0 | 0 | 0 |
G | 0 | 0 | 1 | 1 | 1 | 1 |
A | 0 | 1 | 1 | 1 | 2 | 2 |
C | 0 | 1 | 1 | 2 | 2 | 2 |
Vztah k dalším problémům
Pro dva struny a , délka nejkratší společná supersequence souvisí s délkou LCS o[3]
The upravit vzdálenost když je povoleno pouze vložení a smazání (žádné nahrazení), nebo když je cena nahrazení dvojnásobkem ceny za vložení nebo smazání, je:
Kód pro řešení dynamického programování
Výpočet délky LCS
Níže uvedená funkce slouží jako vstupní sekvence X [1..m]
a Y [1..n]
, počítá LCS mezi X [1..i]
a Y [1..j]
pro všechny 1 ≤ i ≤ m
a 1 ≤ j ≤ n
a ukládá jej do C [i, j]
. C [m, n]
bude obsahovat délku LCS z X
a Y
.
funkce LCSLength (X [1..m], Y [1..n]) C = pole (0..m, 0..n) pro i: = 0..m C [i, 0] = 0 pro j: = 0..n C [0, j] = 0 pro i: = 1..m pro j: = 1..n -li X [i] = Y [j] // i-1 a j-1 při čtení X & Y z nuly C [i, j]: = C [i-1, j-1] + 1 jiný C [i, j]: = max (C [i, j-1], C [i-1, j]) vrátit se C [m, n]
Alternativně, memorování lze použít.
Příklad v C #
statický int[,] LcsLength(tětiva A, tětiva b){ int[,] C = Nový int[A.Délka + 1, b.Délka + 1]; // (a, b). Délka + 1 pro (int i = 0; i < A.Délka; i++) C[i, 0] = 0; pro (int j = 0; j < b.Délka; j++) C[0, j] = 0; pro (int i = 1; i <= A.Délka; i++) pro (int j = 1; j <= b.Délka; j++) { -li (A[i - 1] == b[j - 1])// i-1, j-1 C[i, j] = C[i - 1, j - 1] + 1; jiný C[i, j] = Matematika.Max(C[i, j - 1], C[i - 1, j]); } vrátit se C;}
Čtení LCS
Následující funkce doprovodné stopy možnosti provedené při výpočtu C
stůl. Pokud jsou poslední znaky v předponách stejné, musí být v LCS. Pokud ne, zkontrolujte, co dalo největšímu LCS vedení a , a učinit stejnou volbu. Stačí si vybrat jednu, pokud jsou stejně dlouhé. Zavolejte funkci pomocí i = m
a j = n
.
funkce backtrack (C [0..m, 0..n], X [1..m], Y [1..n], i, j) -li i = 0 nebo j = 0 vrátit se "" -li X [i] = Y [j] vrátit se ústupek (C, X, Y, i-1, j-1) + X [i] -li C [i, j-1]> C [i-1, j] vrátit se ústupek (C, X, Y, i, j-1) vrátit se ústupek (C, X, Y, i-1, j)
Příklad v C #
tětiva Backtrack(int[,] C, char[] aStr, char[] bStr, int X, int y){ -li (X == 0 | y == 0) vrátit se ""; -li (aStr[X - 1] == bStr[y - 1]) // x-1, y-1 vrátit se ústupek(C, aStr, bStr, X - 1, y - 1) + aStr[X - 1]; // x-1 -li (C[X, y - 1] > C[X - 1, y]) vrátit se ústupek(C, aStr, bStr, X, y - 1); vrátit se ústupek(C, aStr, bStr, X - 1, y);}
Čtení všech LCS
Pokud si vyberete a dá stejně dlouhý výsledek, přečte obě výsledné podsekvence. To je vráceno jako sada touto funkcí. Všimněte si, že tato funkce není polynomická, protože pokud jsou řetězce podobné, může se větvit téměř v každém kroku.
funkce backtrackAll (C [0..m, 0..n], X [1..m], Y [1..n], i, j) -li i = 0 nebo j = 0 vrátit se {""} -li X [i] = Y [j] vrátit se {Z + X [i] pro všechny Z v backtrackAll (C, X, Y, i-1, j-1)} R: = {} -li C [i, j-1] ≥ C [i-1, j] R: = backtrackAll (C, X, Y, i, j-1) -li C [i-1, j] ≥ C [i, j-1] R: = R ∪ backtrackAll (C, X, Y, i-1, j) vrátit se R
Vytiskněte rozdíl
Tato funkce provede zpětný posun v matici C a vytiskne rozdíl mezi těmito dvěma sekvencemi. Všimněte si, že při výměně dostanete jinou odpověď ≥
a <
, s >
a ≤
níže.
funkce printDiff (C [0..m, 0..n], X [1..m], Y [1..n], i, j) -li i> = 0 a j> = 0 a X [i] = Y [j] printDiff (C, X, Y, i-1, j-1) tisk „“ + X [i] jinak pokud j> 0 a (i = 0 nebo C [i, j-1] ≥ C [i-1, j]) printDiff (C, X, Y, i, j-1) tisk "+" + Y [j] jinak pokud i> 0 a (j = 0 nebo C [i, j-1]jiný tisk ""
Příklad
Nechat být „XMJYAUZ
" a být „MZJAWXU
“. Nejdelší společná posloupnost mezi a je "MJAU
“. Stůl C
níže, který je generován funkcí Délka LCSL
, ukazuje délky nejdelších běžných subsekvencí mezi předponami a . The th řádek a tento sloupec ukazuje délku LCS mezi a .
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ||
---|---|---|---|---|---|---|---|---|---|
Ó | M | Z | J | A | Ž | 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 |
The zvýrazněno čísla ukazují cestu funkce ústupek
by při čtení LCS následoval z pravého dolního rohu do levého horního rohu. Pokud jsou aktuální symboly v a jsou si rovni, jsou součástí LCS a jdeme nahoru i doleva (zobrazeno v tučně). Pokud ne, jdeme nahoru nebo doleva, podle toho, která buňka má vyšší číslo. To odpovídá buď užívání LCS mezi a nebo a .
Optimalizace kódu
Pro výše uvedený algoritmus lze provést několik optimalizací, které ho zrychlí pro případy z reálného světa.
Snižte problém
Matice C v naivním algoritmu kvadraticky roste s délkami sekvencí. Pro dvě sekvence 100 položek by byla zapotřebí matice 10 000 položek a bylo by třeba provést 10 000 srovnání. Ve většině případů v reálném světě, zejména u rozdílů a oprav zdrojového kódu, se počátky a konce souborů zřídka mění a téměř jistě ne oba současně. Pokud se uprostřed posloupnosti změnilo jen několik položek, lze eliminovat začátek a konec. To snižuje nejen požadavky na paměť pro matici, ale také počet srovnání, která je třeba provést.
funkce LCS (X [1..m], Y [1..n]) start: = 1 m_end: = m n_end: = n na začátku ořízněte odpovídající položky zatímco start ≤ m_end a start ≤ n_end a X [start] = Y [start] start: = start + 1 na konci ořízněte odpovídající položky zatímco start ≤ m_end a start ≤ n_end a X [m_end] = Y [n_end] m_end: = m_end - 1 n_end: = n_end - 1 C = pole (start-1..m_end, start-1..n_end) pouze smyčka přes položky, které se změnily pro i: = start..m_end pro j: = start..n_end algoritmus pokračuje jako předtím ...
V nejlepším případě, sekvence bez změn, by tato optimalizace zcela eliminovala potřebu matice C. V nejhorším případě, změna na první a poslední položku v pořadí, se provedou pouze dvě další srovnání.
Zkraťte dobu porovnání
Většinu času naivní algoritmus stráví srovnáváním položek v sekvencích. U textových sekvencí, jako je zdrojový kód, chcete místo jednotlivých znaků zobrazit řádky jako prvky sekvence. To může znamenat srovnání relativně dlouhých řetězců pro každý krok v algoritmu. Lze provést dvě optimalizace, které mohou pomoci zkrátit čas, který tato srovnání spotřebují.
Omezte řetězce na hodnoty hash
A hashovací funkce nebo kontrolní součet lze použít ke zmenšení velikosti řetězců v sekvencích. To znamená, že u zdrojového kódu, kde je průměrný řádek dlouhý 60 nebo více znaků, může být hash nebo kontrolní součet pro tento řádek dlouhý pouze 8 až 40 znaků. Randomizovaná povaha hashů a kontrolních součtů by navíc zaručila, že se srovnání zkrátí rychleji, protože řádky zdrojového kódu budou na začátku zřídka změněny.
Tato optimalizace má tři hlavní nevýhody. Nejprve je třeba předem věnovat určitý čas předběžnému výpočtu hodnot hash pro dvě sekvence. Zadruhé je třeba přidělit další paměť pro nové hašované sekvence. Ve srovnání s zde použitým naivním algoritmem jsou však obě tyto nevýhody relativně minimální.
Třetí nevýhodou je kolize. Protože není zaručeno, že kontrolní součet nebo hash bude jedinečný, je malá šance, že by dvě různé položky mohly být redukovány na stejný hash. To je ve zdrojovém kódu nepravděpodobné, ale je to možné. Kryptografický hash by proto byl pro tuto optimalizaci mnohem vhodnější, protože jeho entropie bude výrazně větší než entropie jednoduchého kontrolního součtu. Výhody však nemusí stát za nastavení a výpočetní požadavky kryptografického hashu pro malé délky sekvencí.
Zmenšete požadovaný prostor
Pokud je požadována pouze délka LCS, lze matici zmenšit na a matice s lehkostí, nebo do a vektor (chytřejší), protože přístup dynamického programování potřebuje pouze aktuální a předchozí sloupce matice. Hirschbergův algoritmus umožňuje konstrukci optimální optimální sekvence ve stejných kvadratických časových a lineárních prostorových mezích.[7]
Další optimalizované algoritmy
Existuje několik algoritmů, které běží rychleji než prezentovaný přístup dynamického programování. Jedním z nich je Algoritmus Hunt – Szymanski, který obvykle běží čas na ), kde je počet shod mezi dvěma sekvencemi.[8] U problémů s omezenou velikostí abecedy se Metoda čtyř Rusů lze použít ke snížení doby chodu algoritmu dynamického programování o logaritmický faktor.[9]
Chování na náhodných řetězcích
Počínaje Chvátal & Sankoff (1975) ,[10] řada vědců zkoumala chování nejdelší běžné délky subsekvence, když jsou dva dané řetězce náhodně vylosovány ze stejné abecedy. Když je velikost abecedy konstantní, očekávaná délka LCS je úměrná délce dvou řetězců a konstanty proporcionality (v závislosti na velikosti abecedy) jsou známé jako Chvátal – Sankoffovy konstanty. Jejich přesné hodnoty nejsou známy, ale horní a dolní hranice jejich hodnot byla prokázána,[11] a je známo, že rostou nepřímo úměrně druhé odmocnině velikosti abecedy.[12] Ukázalo se, že zjednodušené matematické modely nejdelšího společného posloupnostního problému jsou kontrolovány Distribuce Tracy – Widom.[13]
Viz také
Reference
- ^ David Maier (1978). "Složitost některých problémů s následnostmi a supersekvencemi". J. ACM. Stiskněte ACM. 25 (2): 322–336. doi:10.1145/322063.322075. S2CID 16120634.
- ^ Wagner, Robert; Fischer, Michael (leden 1974). "Problém s opravou řetězce na řetězec". Deník ACM. 21 (1): 168–173. CiteSeerX 10.1.1.367.5281. doi:10.1145/321796.321811. S2CID 13381535. Citováno 2018-05-03.
- ^ A b L. Bergroth a H. Hakonen a T. Raita (2000). "Průzkum nejdelších běžných algoritmů následné posloupnosti". SPIRE. IEEE Computer Society. 00: 39–48. doi:10.1109 / SPIRE.2000.878178. ISBN 0-7695-0746-8. S2CID 10375334.
- ^ Ronald I.Greenberg (06.06.2003). "Meze počtu nejdelších běžných následností". arXiv:cs.DM/0301030.
- ^ Xia, Xuhua (2007). Bioinformatika a buňka: moderní výpočetní přístupy v genomice, proteomice a transkriptomice. New York: Springer. str.24. ISBN 978-0-387-71336-6.
- ^ Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest a Clifford Stein (2001). "15.4". Úvod do algoritmů (2. vyd.). MIT Press a McGraw-Hill. 350–355. ISBN 0-262-53196-8.CS1 maint: více jmen: seznam autorů (odkaz)
- ^ Hirschberg, D. S. (1975). Msgstr "Algoritmus lineárního prostoru pro výpočet maximálních společných posloupností". Komunikace ACM. 18 (6): 341–343. doi:10.1145/360825.360861. S2CID 207694727.
- ^ Apostolico, Alberto; Galil, Zvi (1997-05-29). Algoritmy shody vzorů. ISBN 9780195354348.
- ^ Masek, William J .; Paterson, Michael S. (1980), "Rychlejší algoritmus pro výpočetní vzdálenosti úprav řetězce", Journal of Computer and System Sciences, 20 (1): 18–31, doi:10.1016/0022-0000(80)90002-1, PAN 0566639.
- ^ Chvatal, Václáv; Sankoff, David (1975), „Nejdelší běžné subsekvence dvou náhodných sekvencí“, Journal of Applied Probability, 12 (2): 306–315, doi:10.2307/3212444, JSTOR 3212444, PAN 0405531.
- ^ Lueker, George S. (2009), „Vylepšené hranice průměrné délky nejdelších běžných subsekvencí“, Deník ACM, 56 (3), A17, doi:10.1145/1516512.1516519, PAN 2536132, S2CID 7232681.
- ^ Kiwi, Marcos; Loebl, Martin; Matoušek, Jiří (2005), „Očekávaná délka nejdelší společné posloupnosti pro velké abecedy“, Pokroky v matematice, 197 (2): 480–498, arXiv:matematika / 0308234, doi:10.1016 / j.aim.2004.10.012, PAN 2173842.
- ^ Majumdar, Satya N .; Nechaev, Sergei (2005), "Přesné asymptotické výsledky pro Bernoulliho srovnávací model sekvenčního zarovnání", Fyzický přehled E, 72 (2): 020901, 4, arXiv:q-bio / 0410012, Bibcode:2005PhRvE..72b0901M, doi:10.1103 / PhysRevE.72.020901, PAN 2177365, PMID 16196539, S2CID 11390762.
externí odkazy
- Slovník algoritmů a datových struktur: nejdelší společná posloupnost
- Kolekce implementací nejdelší společné posloupnosti v mnoha programovacích jazycích
- Najděte nejdelší společnou posloupnost v Pythonu