Setelah saya belajar bagaimana membangun array sufiks dalam kompleksitas , saya tertarik untuk menemukan aplikasi array sufiks. Salah satunya adalah menemukan substring umum terpanjang antara dua string, dalam waktu . Saya menemukan di internet algoritma berikut:
- menggabungkan kedua string dan menjadi satu string
- hitung susunan sufiks
- hitung larik (awalan umum terpanjang)
- jawabannya adalah nilai terbesar
Saya mencoba mengimplementasikannya, tetapi karena banyak detail implementasi tidak disebutkan (yaitu ketika menggabungkan string, haruskah saya menempatkan karakter khusus di antara mereka ( )?), Kode saya gagal pada banyak kasus uji. Bisakah seseorang menguraikan lebih lanjut tentang algoritma ini?
Terima kasih sebelumnya.
Catatan: Saya tidak menjamin kebenaran dari algoritma ini; Saya menemukannya di blog, dan saya tidak yakin itu berfungsi. Jika menurut Anda itu salah, harap sarankan algoritma lain.
sumber
Jawaban:
Algoritme Anda salah . Saya berasumsi Anda tahu bagaimana menghitung array suffix dan array LCP dari sebuah string, yaitu implementasi yang efisien. Seperti yang telah ditunjukkan dalam komentar, Anda harus mencoba memahami apa yang masing-masing komponen, dan mengapa itu bekerja.
Pertama-tama, adalah array suffix ( ) dari sebuah string. Susunan sufiks pada dasarnya adalah semua sufiks dari string S yang disusun dalam urutan leksikografis naik. Lebih khusus, nilai S A [ i ] menunjukkan bahwa akhiran dari S mulai dari posisi S A [ i ] adalah peringkat saya dalam pemesanan leksikografis semua akhiran dari S .SA S SA[i] S SA[i] i S
Berikutnya adalah array L C P [ i ] menunjukkan panjang awalan umum terpanjang antara sufiks mulai dari S A [ i - 1 ] dan S A [ i ] . Yaitu, ia melacak panjang awalan umum terpanjang di antara dua sufiks S berturut-turut ketika disusun dalam urutan leksikografis.LCP LCP[i] SA[i−1] SA[i] S
Sebagai contoh, perhatikan string . Sufiks dalam susunan leksikografis adalah { 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 } , jadi S A = [ 7 , 1S=abbabca {a,abbabca,abca,babca,bbabca,bca,ca} untuk array 1-diindeks. The L C P array yang akan L C P = [ - , 1 , 2 , 0 , 1 , 1 , 0 ] .SA=[7,1,4,3,2,5,6] LCP LCP=[−,1,2,0,1,1,0]
Sekarang, diberikan dua string dan B , kita menggabungkan mereka sebagai S = A # B , di mana # adalah karakter tidak hadir di kedua A dan B . Alasan untuk memilih karakter seperti itu adalah bahwa ketika menghitung LCP dari dua sufiks, katakan a b # d a b d dan a b d , perbandingan akan terputus pada akhir string pertama (karena hanya terjadi sekali, dua sufiks yang berbeda tidak akan pernah berada di posisi yang sama), dan tidak akan "meluap" ke string lain.A B S=A#B # A B ab#dabd abd
Sekarang, dapat dilihat bahwa Anda harus dapat melihat mengapa Anda hanya perlu melihat nilai-nilai berturut-turut dalam array (argumen didasarkan pada kontradiksi dan fakta bahwa sufiks dalam S A berada dalam urutan leksikografis). Terus periksa array L C P untuk nilai maksimum sehingga dua sufiks yang dibandingkan tidak menjadi milik string asli yang sama. Jika mereka tidak termasuk string asli yang sama (satu dimulai pada A dan yang lain dalam B ), maka nilai terbesar adalah panjang substring umum terbesar.LCP SA LCP A B
Sebagai contoh, pertimbangkan dan B = b c . Kemudian, S = a b c a b c # b c . Sufiks yang diurutkan adalah { a b c # b c , a b c a b c # b c , b c , b c # b c , b c aA=abcabc B=bc S=abcabc#bc {abc#bc,abcabc#bc,bc,bc#bc,bcabc#bc,c,c#bc,cabc#bc} .
SALCP=[4,1,8,5,2,9,6,3,7]=[−,3,0,2,2,0,1,1,0]
Now, the greatest value isLCP[2]=3 , but it is for SA[1] and SA[2] , both of which start in the string A . So, we ignore that. On the other hand, LCP[4]=2 is for SA[3] (corresponds to the suffix bc of B ) and SA[4] (corresponding to suffix 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 .
sumber
{#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]
andLCP=[−,0,3,0,2,2,0,1,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.
sumber
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.
sumber