Обчислення найдовшої загальної підрядки з двох рядків за допомогою суфіксних масивів


15

Після того, як я дізнався, як будувати суфіксний масив за складністю O(N) , мені цікаво розкрити програми суфіксних масивів. Одне з них - це знаходження найдовшої загальної підрядки між двома рядками за O(N) часом. Я знайшов в Інтернеті такий алгоритм:

  1. об'єднайте два рядки A і B в один рядок AB
  2. обчислити суфіксний масив AB
  3. обчислити масив LCP (найдовший загальний префікс)
  4. відповідь - найбільше значення LCP[i]

Я намагався його реалізувати, але так як багато деталей реалізації не було сказано (тобто, при об'єднанні рядків, чи слід вставляти між ними спеціальний символ ( )?), Мій код не вдався в багатьох тестових випадках. Чи може хтось детальніше розробити цей алгоритм?AcB

Заздалегідь спасибі.

Примітка: я не гарантую правильність цього алгоритму; Я знайшов це в блозі, і не впевнений, що це працює. Якщо ви вважаєте, що це неправильно, запропонуйте інший алгоритм.


3
Перш ніж реалізувати алгоритм, спробуйте зрозуміти, чому він працює. Це може допомогти відповісти на запитання, як поєднати два рядки.
Yuval Filmus

3
Я сумніваюся у правильності цього алгоритму. Візьміть і b c d , як я прочитав це поверне a b c d , що невірно. abcdabcdbcdabcd
Хаур

Відповіді:


20

Ваш алгоритм невірний . Я припускаю, що ви знаєте, як обчислити суфіксний масив та LCP масив рядка, тобто їх ефективну реалізацію. Як було зазначено в коментарях, ви повинні спробувати зрозуміти, що таке кожен компонент, і чому він працює.

Перш за все, це суфіксний масив ( ) рядка. Суфіксний масив - це в основному всі суфікси рядка S, розташовані у порядку зростання лексикографічного порядку. Більш конкретно, значення S A [ i ] вказує на те, що суфікс S, що починається з позиції S A [ i ] , класифікується iSASSA[i]SSA[i]i в лексикографічному упорядкуванні всіх суфіксів .S

Далі - масив L C P [ i ] позначає довжину найдовшого загального префікса між суфіксами, починаючи з S A [ i - 1 ] та S A [ i ] . Тобто він відслідковує довжину найдовшого загального префікса серед двох послідовних суфіксів S, якщо вони розташовані в лексикографічному порядку.LCPLCP[i]SA[i1]SA[i]S

Як приклад, розглянемо рядок . Суфікси в лексикографічному порядку були б { a , a b b a b c a , a b c a , b a b c a , b b a b c a , b c a , c a } , так S A = [ 7 , 1S=abbabca{a,abbabca,abca,babca,bbabca,bca,ca} для 1-індексованого масиву. Л С Р масив буде Ь С Р = [ - , 1 , 2 , 0 , 1 , 1 ,SA=[7,1,4,3,2,5,6]LCP .LCP=[,1,2,0,1,1,0]

Тепер, з огляду на два рядки і B , ми зчепити їх , як S = A # B , де # це символ не присутній в обох A і B . Причина вибору такого символу полягає в тому, що при обчисленні LCP двох суфіксів скажіть a b # d a b d і a bABS=A#B#ABab#dabd , порівняння розривається в кінці першого рядка (оскільки воно відбувається лише один раз, два різні суфікси ніколи не матимуть його в одному положенні) і не будуть"переповнюватися"в інший рядок.abd

Тепер видно, що ви повинні мати можливість бачити, чому вам потрібно бачити лише послідовні значення в масиві (аргумент заснований на суперечності та тому, що суфікси в S A знаходяться в лексикографічному порядку). Продовжуйте перевіряти масив L C P на максимальне значення таким чином, щоб два суфікси, що порівнюються, не належали до однієї оригінальної рядки. Якщо вони не належать до однієї і тієї самої початкової рядки (одна починається з A, а друга в B ), то найбільшим таким значенням є довжина найбільшої загальної підрядки.LCPSALCPAB

Як приклад, розглянемо і B = b c . Тоді S = a b c a b c # b c . Відсортовані суфікси { a b c # b c , a b c a b c # b c , b c , b c # b c , b c aA=abcabcB=bcS=abcabc#bc . S A{abc#bc,abcabc#bc,bc,bc#bc,bcabc#bc,c,c#bc,cabc#bc}
SA=[4,1,8,5,2,9,6,3,7]LCP=[,3,0,2,2,0,1,1,0]

LCP[2]=3SA[1]SA[2]ALCP[4]=2SA[3]bcBSA[4]bcabc#bcA2 LCPSA[3]SA[4]bc


1
Excellent explanation but I think that the example is a bit wrong, the sorted suffixes are : {#bc,abc#bc,abcabc#bc,bc,bc#bc,bcabc#bc,c,c#bc,cabc#bc}, SA=[7,4,1,8,5,2,9,6,3] and LCP=[−,0,3,0,2,2,0,1,1]
Saúl Martínez Vidals

1

The algorithm you found online is not entirely correct. As mentioned by Paresh, it will fail in the example given by him.

However, if you ensure that while checking the LCP, you only check the LCP of substrings of different strings. For example, if you are finding the LCS of strings A and B, then you need to ensure that the adjacent entries of the Suffix Array while checking for LCP are both not from the same string.

More details here.


1
When you say "This answer", do you mean your own answer or some other answer? Please only use the answer box to answer the question, not to comment on other answers. When you've picked up enough reputation, you'll be able to leave comments on other answers.
David Richerby

0

I think something like the algorithm you cite should indeed work if a character that is not part of the character set is used as a separator, and the suffix/prefix arrays are built to exclude all strings that contain the separator, probably the intention of the designer. this is basically equivalent to building suffix/prefix arrays for the two separate strings.

it would be helpful for future ref if you posted a link to the algorithm. note that wikipedia has the algorithm for this in pseudocode & many other algorithms. and there are implementations in most standard languages available online.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.