Algoritma pencocokan string k tidak cocok cepat

10

Saya mencari algoritma pencocokan string k-mismatch yang cepat. Diberikan string pola P dengan panjang m, dan string teks T dengan panjang n, saya memerlukan algoritma cepat (waktu linear) untuk menemukan semua posisi di mana P cocok dengan substring T dengan paling banyak k ketidakcocokan. Ini berbeda dari masalah k-perbedaan (jarak edit). Ketidakcocokan menyiratkan substring dan pola memiliki huruf yang berbeda di sebagian besar posisi k. Saya benar-benar hanya memerlukan k = 1 (paling banyak 1 mismatch), jadi algoritma cepat untuk kasus spesifik k = 1 juga sudah cukup. Ukuran alfabet adalah 26 (teks bahasa Inggris case-insensitive), jadi kebutuhan ruang tidak boleh tumbuh terlalu cepat dengan ukuran alfabet (mis., Algoritma FAAST, saya percaya, membutuhkan ruang eksponensial dalam ukuran alfabet, dan sebagainya hanya cocok untuk sekuens protein dan gen).

Pendekatan berbasis pemrograman dinamis akan cenderung menjadi O (mn) dalam kasus terburuk, yang akan terlalu lambat. Saya percaya ada modifikasi dari algoritma Boyer-Moore untuk ini, tetapi saya tidak bisa mendapatkan kertas-kertas tersebut. Saya tidak memiliki langganan untuk mengakses jurnal atau publikasi akademis, jadi referensi apa pun harus ada dalam domain publik.

Saya akan sangat menghargai setiap petunjuk, atau referensi ke dokumen yang tersedia secara bebas, atau algoritma itu sendiri untuk masalah ini.

Paresh
sumber
2
Jika polanya diperbaiki (tetapi teks yang cocok bervariasi), Anda berpotensi membuat otomat terbatas dan menjalankan teks itu. Ada juga algoritma yang menggunakan pohon sufiks (biasanya bagus jika teksnya konstan dan polanya bervariasi, tetapi juga berlaku jika keduanya bervariasi), Anda mungkin dapat menemukan beberapa referensi di web. (Belum menambahkan jawaban karena saya belum yakin tentang algoritma berbasis suffix tree, jika ada yang tahu, silakan abaikan komentar ini).
Aryabhata
@Aryabhata Terima kasih! Pola dan teks berubah. Dalam konteks itu, membangun otomat terbatas akan terlalu mahal, terutama ketika termasuk ruang untuk 1 ketidakcocokan. Adapun pohon sufiks / susunan sufiks, saya belum pernah menggunakannya, dan tahu sedikit tentang mereka, tetapi berada di bawah kesan bahwa mereka lambat untuk membangun dan efisien terutama untuk pencocokan tepat. Tapi saya akan mengeksplorasi opsi ini lebih lanjut. Petunjuk apa pun dalam arah ini, atau ke arah lain mana pun akan sangat berguna!
Paresh
1
Tidak, pohon sufiks juga dapat digunakan untuk perkiraan kecocokan. Atleast mengklaim wiki demikian: en.wikipedia.org/wiki/Suffix_tree
Aryabhata

Jawaban:

5

Array sufiks dapat digunakan untuk masalah ini. Mereka berisi posisi awal setiap sufiks dari string yang diurutkan dalam urutan leksikografis. Meskipun mereka dapat dibangun secara naif di kompleksitas, ada metode untuk membangun mereka dalam Θ ( n ) kompleksitas. Lihat misalnya ini dan ini . Mari kita sebut array sufiks SA ini.O(nlogn)Θ(n)

Setelah susunan sufiks dibangun, kita perlu membuat susunan Longest Common Prefix (LCP) untuk susunan sufiks. Array LCP menyimpan panjang awalan umum terpanjang antara dua awalan berurutan dalam susunan sufiks (sufiks berturut-turut leksikografis). Dengan demikian, LCP [i] berisi panjang awalan umum terpanjang antara SA [i] dan SA [i + 1]. Array ini juga dapat dibangun dalam waktu linier: lihat di sini , di sini dan di sini untuk beberapa referensi yang bagus.

uvu<vminu<=k<=v1LCP[k]LCPO(n)O(nlogn)LCP[u,v]O(1)

iTLCPTiPPT[i]l0TPLCPT[i+l0+1]P[l0+1]kLCPO(1)O(k) LCPiTO(nk)

O(nk+(n+m)log(n+m))O(nk+nlogn)m=O(n)O(nk)

Paresh
sumber
Bagus! Saya punya beberapa bacaan di daftar TODO saya sekarang :-)
Aryabhata
Tautan siam.org di paragraf kedua rusak, tetapi makalah yang ditautkan dapat ditemukan di sini epubs.siam.org/doi/pdf/10.1137/1.9781611972917.3
leecbaker
4

O(n+m)kO(nk+m)

Idenya mirip dengan algoritma hash rolling Rabin-Karp untuk pencocokan substring yang tepat.

m2km/2k2k2k

k

k

Saya berharap (peringatan: belum mencobanya sendiri) ini mungkin akan lebih cepat dalam praktek, dan mungkin lebih mudah untuk kode / memelihara, daripada menggunakan pendekatan berbasis pohon suffix.

Aryabhata
sumber
Hanya perlu klarifikasi. Dengan "..pisahkan setiap string dengan panjang m menjadi 2k blok dengan ukuran m / 2k masing-masing ...", maksud Anda, pisahkan setiap substring panjang m dalam T (dengan panjang n) menjadi 2k blok. Dan hash ini dapat dihitung dalam O (n) dengan metode hash bergulir. Kemudian, string pola juga akan dibagi menjadi 2k blok, dan hash yang sesuai akan dibandingkan, memberikan kelonggaran untuk paling banyak k blok untuk ketidakcocokan. Jika demikian, maka kita akan dapat berpotensi membuang semua kasus di mana jumlah ketidakcocokan lebih dari k. Apakah saya mengerti benar?
Paresh
kΩ(nk)O(n)
Saya suka pendekatan ini! Namun, pendekatan ini umumnya cepat, tetapi menurun menjadi O (mnk) jika jumlah kecocokan tinggi (O (n) kecocokan). Dengan mengingat hal ini, saya mempertahankan dua hash bergulir, dengan asumsi bahwa keduanya tidak dapat memiliki tabrakan untuk input yang sama (saya tidak melakukan ini secara matematis karena saya ingin melihat kecepatan). Dengan cara ini, kita tidak perlu memverifikasi char-by-char pertandingan jika kedua hash setuju. Ini cukup cepat secara umum, tetapi ini juga lambat jika jumlah pertandingan besar. Dengan ini dan dengan cara yang Anda sarankan, itu lambat untuk pertandingan besar.
Paresh
mm/2kmO(nkm)
mm/2k2kk+1k+cΩ(nm)mm/2k