Kalıp #35
KMP / String Matching
İleriFailure fonksiyonuyla doğrusal zamanlı pattern eşleştirme; rolling hash.
Ne zaman kullanılır
Bir metinde patterni O(n + m)'de aramak için. Tam eşleştirme için failure (LPS) dizili KMP; çoklu pattern veya kayan hash için rolling hash (Rabin-Karp).
Tanıma ipuçları
- Patterni doğrusal zamanda bul
- Yinelenen alt string / LPS dizisi
- Kayan pencerede rolling hash
- Çoklu pattern eşleştirme
Yaygın tuzaklar
- LPS dizisini yanlış kurmak (off-by-one)
- Rabin-Karp hash çakışması (double hash veya doğrula)
- Rolling hashde modüler overflow
90 saniyelik tanıma egzersizi
Hangisi en iyi uyuyor?
- Patterni doğrusal zamanda bul
- Yinelenen alt string / LPS dizisi
- Kayan pencerede rolling hash
Etkileşimli
Zihinsel model
Değişmezin tam adım adım anlatımı. Duraklat, noktalara tıkla veya ← → kullan. Her adımı kendi cümlelerinle anlatmayı hedefle.
pattern = ABAB
Metinde pattern ABAB bul. Naif eşleştirme uyumsuzlukta baştan başlar; KMP öneki yeniden kullanır.
Nasıl düşünülür
Naif eşleştirme O(n*m)’dir: her konumda patterni karşılaştır, uyumsuzlukta geri dön. KMP geri dönüşü longest-prefix-suffix (LPS) dizisi ile ortadan kaldırır: lps[i], patternin pattern[0..i] sonekuyla aynı olan en uzun proper önekidir. j konumunda uyumsuzlukta, yeniden başlatmak yerine j’yi lps[j-1]’e atla, o kadar karakteri zaten eşleştin. LPS dizisini bir kez kur (O(m)), sonra metni bir tara (O(n)).
Rabin-Karp farklı bir yol izler: patterni hash’le, sonra metin boyunca hash’i kaydır. Rolling hash O(1)’de güncellenir (çıkan karakteri çıkar, base ile çarp, giren karakteri ekle, mod al). Hash patternin hash’ine eşit olduğunda, çakışmayı ekarte etmek için karakter karakter doğrula. Çoklu pattern eşleştirmede (hash set) veya metin akışında parlar.
Şablon şekilleri
| Şekil | Temel hamle | Örnek |
|---|---|---|
| KMP tam eşleştirme | LPS kur; metni atlama ile tara | LC 28 |
| En kısa palindrom | pattern + reverse(pattern)’in LPS’i | LC 214 |
| En uzun mutlu önek | Stringin kendisinin LPS’i | LC 1392 |
| Rabin-Karp rolling hash | Pattern hash’le; metinde hash kaydır | LC 3036 |
Karmaşıklık temeli
KMP: O(n + m) zaman, O(m) alan (LPS). Rabin-Karp: ortalama O(n + m), worst case O(n*m) (çok çakışma); double hash ile çakışmaları ihmal edilebilir yap. Rolling hash güncelleme: O(1).
Şablondan probleme
- Tek pattern tam eşleştirme mi? → KMP. Çoklu pattern veya kayan? → Rabin-Karp.
- LPS dizisini dikkatli kur,
lps[i]i’den önceki önek uzunluğudur,i’dekinin değil. - Rabin-Karp için alfabeden büyük bir base ve büyük asal seç; her adımda mod al.
- Hash eşleşmesini döndürmeden önce her zaman karakter kontrolüyle doğrula.
Şablon
TypeScript, Python ve C#’te aynı iskelet. Değişmezi uyarla; yapıyı koru.
/** KMP template: build LPS array and find pattern in text. */
export function buildLps(pattern: string): number[] {
const lps = new Array<number>(pattern.length).fill(0);
let len = 0;
for (let i = 1; i < pattern.length; i++) {
while (len > 0 && pattern[i] !== pattern[len]) len = lps[len - 1]!;
if (pattern[i] === pattern[len]) len++;
lps[i] = len;
}
return lps;
}
export function kmpSearch(text: string, pattern: string): number {
if (pattern.length === 0) return 0;
const lps = buildLps(pattern);
let j = 0;
for (let i = 0; i < text.length; i++) {
while (j > 0 && text[i] !== pattern[j]) j = lps[j - 1]!;
if (text[i] === pattern[j]) j++;
if (j === pattern.length) return i - j + 1;
}
return -1;
}/** KMP template: build LPS array and find pattern in text. */
export function buildLps(pattern: string): number[] {
const lps = new Array<number>(pattern.length).fill(0);
let len = 0;
for (let i = 1; i < pattern.length; i++) {
while (len > 0 && pattern[i] !== pattern[len]) len = lps[len - 1]!;
if (pattern[i] === pattern[len]) len++;
lps[i] = len;
}
return lps;
}
export function kmpSearch(text: string, pattern: string): number {
if (pattern.length === 0) return 0;
const lps = buildLps(pattern);
let j = 0;
for (let i = 0; i < text.length; i++) {
while (j > 0 && text[i] !== pattern[j]) j = lps[j - 1]!;
if (text[i] === pattern[j]) j++;
if (j === pattern.length) return i - j + 1;
}
return -1;
}- 1#28 Find the Index of the First Occurrence in a StringRehbereasy
- 2#1392 Longest Happy PrefixRehberhard
- 3#1408 String Matching in an ArrayRehbereasy
- 4#214 Shortest PalindromeRehberhard
- 5#459 Repeated Substring PatternRehbereasy
- 6#3036 Number of Subarrays That Match a Pattern IIRehberhard