Sonek dizileri kullanarak iki dizenin en uzun ortak alt dizesini hesaplama


15

karmaşıklığında bir sonek dizisi oluşturmayı öğrendikten sonra , sonek dizilerinin uygulamalarını keşfetmekle ilgileniyorum. Bunlardan biri, O ( N ) zamanında iki tel arasındaki en uzun ortak alt dizeyi bulmaktır . İnternette aşağıdaki algoritmayı buldum:O(N)O(N)

  1. iki ve B dizesini bir B dizesine birleştirinABAB
  2. A B sonek dizisini hesaplarAB
  3. (en uzun ortak önek) dizisini hesaplarLCP
  4. cevap en büyük değerdir LCP[i]

Uygulamayı denedim, ancak birçok uygulama detayı söylenmediği gibi (yani dizeleri birleştirirken aralarına özel bir karakter koymalıyım ( )?), Kodum birçok test durumunda başarısız oldu. Birisi bu algoritma hakkında daha fazla ayrıntı verebilir mi?AcB

Şimdiden teşekkürler.

Not: Bu algoritmanın doğruluğunu garanti etmiyorum; Bir blogda buldum ve çalıştığından emin değilim. Bunun yanlış olduğunu düşünüyorsanız, lütfen başka bir algoritma önerin.


3
Algoritmayı uygulamadan önce, neden çalıştığını anlamaya çalışın. Bu, iki dizeyi nasıl birleştireceğiniz gibi bir sorunun yanıtlanmasına yardımcı olabilir.
Yuval Filmus

3
Bu algoritmanın doğruluğundan şüpheliyim. Al ve b c d , okudum yolu dönecektir bir b c d yanlıştır. abcdabcdbcdabcd
Khaur

Yanıtlar:


20

Algoritmanız yanlış . Bir dizenin sonek dizisini ve LCP dizisini, yani etkin uygulamalarını nasıl hesaplayacağınızı bildiğinizi varsayalım. Yorumlarda belirtildiği gibi, her bir bileşenin ne olduğunu ve neden çalıştığını anlamaya çalışmalısınız.

Her şeyden önce, son ek dizisi (bir bir zincir). Bir sonek dizisi temel olarak S dizgesinin artan sözlükbilimsel düzende düzenlenmiş tüm sonekleridir . Daha spesifik olarak, bir değer S A [ I ] arasında eki göstermektedir S konumu itibaren G A [ i ] sıralanır i her soneklerinin lexicographic sıralamada S .SASSA[i]SSA[i]iS

Sıradaki dizisidir. L Cı- p [ i ] uzun ortak uzunluğunu belirten bir önek ile son ekler itibaren G A [ i - 1 ] ve G A [ I ] . Yani, sözlükbilimsel düzende düzenlendiğinde birbirini izleyen iki S soneki arasındaki en uzun ortak önek uzunluğunu izler .LCPLCP[i]SA[i1]SA[i]S

Örnek olarak, dizesini ele alalım . Sözcükbilimsel sıradaki sonekler { 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 } , yani S A = [ 7 , 1S=abbabca{a,abbabca,abca,babca,bbabca,bca,ca} . L Cı- P bir dizi olacaktır L Cı- p = [ - , 1 , 2 , 0 , 1 , 1SA=[7,1,4,3,2,5,6]LCP .LCP=[,1,2,0,1,1,0]

Şimdi, iki dizeleri verilen ve B , biz onları bağlamak S = A # B , # hem mevcut değil karakterdir A ve B . Böyle bir karakteri seçmenin nedeni, iki son ekin LCP'sini hesaplarken, örneğin bir b # d a b d ve a b d , karşılaştırma ilk dizenin sonunda kopacaktır (yalnızca bir kez gerçekleştiği için, iki farklı sonek asla aynı konumda olmaz) ve diğer dizeye "taşmaz" .ABS=A#B#ABab#dabdabd

Şimdi, neden sadece dizisinde ardışık değerleri görmeniz gerektiğini görebiliyor olmalısınız (argüman çelişkiye ve S A'daki soneklerin sözlükbilimsel düzende olduğu gerçeğine dayanmaktadır ). Kontrol etmeye devam L Cı- P maksimum değer için bir dizi bu tür iki ekleri karşılaştırılan aynı orijinal dizeye ait değil. Aynı orijinal dizeye ait değilse (biri A'da diğeri B'de başlar ), bu durumda en büyük değer en büyük ortak alt dizenin uzunluğudur.LCPSALCPAB

Örnek olarak ve B = b c'yi düşünün . Sonra S = a b c a b c # b c . Sıralanan sonekler { 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{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#bc of A). So, this is the longest common substring between the two strings. For getting the actual substring, you take a length 2 (value of the greatest feasible LCP) substring starting from either SA[3] or SA[4], which is 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.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.