Bölüm 5.1: Dizgi Eşleştirme ve Sıkıştırma
Çıktı Sorusu · Kaba Kuvvet
Soru 1: Kaç Karşılaştırma?
Dersteki kabaKuvvet metodu kabaKuvvet("abracacadabra", "cad") çağrısında hangi değeri döndürür ve toplam kaç karakter karşılaştırması yapar?
int kabaKuvvet(String t, String p) { int n = t.length(), m = p.length(); for (int i = 0; i <= n - m; i++) { int j = 0; while (j < m && t.charAt(i + j) == p.charAt(j)) j++; if (j == m) return i; } return -1; }
Cevabı göster
Dönüş: 6 · karşılaştırma: 11
- s = 0, 1, 2, 3: ilk karakter (a, b, r, a) ≠ c → 4 × 1 = 4
- s = 4: c = c, a = a, c ≠ d → 3
- s = 5: a ≠ c → 1
- s = 6: c, a, d eşleşir → 3; j == m olduğu için 6 döner
4 + 3 + 1 + 3 = 11. Uyuşmazlıkta öğrenilen bilgi atılır; örüntü her seferinde yalnızca 1 kayar.
Çoktan Seçmeli · Kaba Kuvvet
Soru 2: Döngü Sınırı Hatası
kabaKuvvet metodundaki i <= n - m koşulu yanlışlıkla i < n - m yazılırsa aşağıdaki çağrılardan hangisi yanlış sonuç (−1) döndürür?
C: n = 5, m = 2 için doğru kaymalar 0..3'tür; hatalı koşul yalnızca 0, 1, 2'yi dener. "em" yalnızca s = 3 = n − m konumunda geçtiği için bulunamaz. "le" s = 2'de olduğu için hâlâ bulunur.
Adım Adım Çalıştırma · Kaba Kuvvet
Soru 3: kabaKuvvet İzleme
kabaKuvvet("AABAABAAC", "AAC") hangi değeri döndürür, kaç karakter karşılaştırması yapılır?
n = 9, m = 3: geçerli kaymalar i = 0..6. Örüntü metnin altına i = 0 hizasında yerleşecek.
i = 0: 2 karakter eşleşti, t[2] = 'B' ≠ p[2] = 'C' → örüntü 1 kayar.
i = 1: 1 karakter eşleşti, t[2] = 'B' ≠ p[1] = 'A' → örüntü 1 kayar.
i = 2: t[2] = 'B' ≠ p[0] = 'A' → ilk karakterde uyuşmazlık, örüntü 1 kayar.
i = 3: 2 karakter eşleşti, t[5] = 'B' ≠ p[2] = 'C' → örüntü 1 kayar.
i = 4: 1 karakter eşleşti, t[5] = 'B' ≠ p[1] = 'A' → örüntü 1 kayar.
i = 5: t[5] = 'B' ≠ p[0] = 'A' → ilk karakterde uyuşmazlık, örüntü 1 kayar.
i = 6: A, A, C üçü de eşleşti; j = 3 = m olunca while döngüsü biter.
j == m → 6 döndürülür. Toplam 15 karşılaştırma; aynı A'lar farklı hizalarda tekrar tekrar okundu.
int kabaKuvvet(String t, String p) { int n = t.length(), m = p.length(); for (int i = 0; i <= n - m; i++) { int j = 0; while (j < m && t.charAt(i + j) == p.charAt(j)) j++; if (j == m) return i; } return -1; }
Çoktan Seçmeli · KMP
Soru 4: LPS Tanımı
lpsHesapla("aaaa") hangi diziyi döndürür?
A: lps[q], P[0..q]'nun kendisine eşit olmayan (uygun) ve aynı zamanda soneki olan en uzun önekidir. "aaaa" için bu "aaa" → 3. B dizginin kendisini de sayar; D ise yalnızca tek karakterlik öneki dener.
Adım Adım Çalıştırma · KMP
Soru 5: lpsHesapla İzleme
lpsHesapla("ababaca") hangi diziyi döndürür?
lps[0] = 0 her zaman (tek karakterin uygun öneki yok). k: o ana kadar eşleşen önek uzunluğu.
p[0] = 'a' ≠ p[1] = 'b' → k = 0 kalır, lps[1] = 0.
p[0] = 'a' = p[2] → k = 1, lps[2] = 1.
p[1] = 'b' = p[3] → k = 2, lps[3] = 2.
p[2] = 'a' = p[4] → k = 3, lps[4] = 3.
p[3] = 'b' ≠ p[5] = 'c' → geri çekil: k = lps[2] = 1.
p[1] = 'b' ≠ p[5] = 'c' → geri çekil: k = lps[0] = 0.
p[0] = 'a' ≠ p[5] = 'c' → k = 0 kalır, lps[5] = 0.
p[0] = 'a' = p[6] → k = 1, lps[6] = 1.
Sonuç: lps = [0, 0, 1, 2, 3, 0, 1]. Toplam geri çekilme toplam artışı aşamaz → O(m).
int[] lpsHesapla(String p) { int m = p.length(), k = 0; int[] lps = new int[m]; for (int q = 1; q < m; q++) { while (k > 0 && p.charAt(k) != p.charAt(q)) k = lps[k - 1]; if (p.charAt(k) == p.charAt(q)) k++; lps[q] = k; } return lps; }
Çoktan Seçmeli · KMP
Soru 6: Uyuşmazlıkta Geri Çekilme
Örüntü "abcabd" için lps = [0, 0, 0, 1, 2, 0]. KMP aramasında metinle "abcab" eşleşmişken (q = 5) sıradaki metin karakteri d değil. q hangi değeri alır ve örüntü kaç konum kaymış olur?
D: q = lps[q − 1] = lps[4] = 2, çünkü "ab" eşleşen "abcab"ın hem öneki hem sonekidir; kayma 5 − 2 = 3. B, lps[q] (lps[5] = 0) kullanma hatasıdır. Metin işaretçisi i geri gitmez; "ab" yeniden karşılaştırılmaz.
Çıktı Sorusu · KMP
Soru 7: Üç Algoritma, Bir Metin
Metin "gel de geleyim", örüntü "geleyim". Kaba kuvvet, KMP ve Boyer-Moore (yalnızca kötü karakter kuralı) ilk eşleşmeyi bulana kadar kaçar karakter karşılaştırması yapar? Eşleşme hangi konumdadır?
Cevabı göster
Eşleşme s = 7. Karşılaştırmalar: kaba kuvvet 17, KMP 15, Boyer-Moore 8.
- Kaba kuvvet: s = 0'da "gel" eşleşir, '␣' ≠ 'e' (4); s = 1..6 ilk karakterde biter (6); s = 7'de 7 → 17.
- KMP (lps hep 0): "gel" (3), '␣' önce p[3] sonra p[0] ile (2), d, e, ␣ (3), geleyim (7) → 15. Metin hiç geri okunmaz.
- Boyer-Moore: s = 0'da sağdan ilk karşılaştırma t[6] = '␣' ≠ 'm'; ␣ örüntüde yok → 7 kaydır; s = 7'de 7 eşleşme → 8.
Çoktan Seçmeli · KMP
Soru 8: KMP Neden Doğrusal?
KMP aramasında while döngüsündeki geri çekilmelerin (q = lps[q - 1]) toplam sayısı neden n'yi aşamaz?
B: Amortize argüman: q her adımda en çok 1 artar (toplam ≤ n), her geri çekilme onu en az 1 azaltır ve q ≥ 0 kalır; bu yüzden toplam geri çekilme ≤ n, arama O(n). C yanlıştır: KMP'de i hiç geri gitmez; A da yanlıştır: lps değerleri m − 1'e kadar çıkabilir.
Çoktan Seçmeli · Boyer-Moore
Soru 9: max(1, …) Neden Var?
Boyer-Moore'da kaydırma s += Math.max(1, j - son[c]) yerine s += j - son[c] yazılırsa ne olur?
A: Örneğin "abacab"da c = a için son = 4'tür; uyuşmazlık j = 3'te çıkarsa 3 − 4 = −1 olur. max(1, …) en az 1 ilerlemeyi garanti eder; yoksa sonsuz döngü ya da geri gitme olur. B yanlıştır: j + 1 kaydırma güvenlidir, çünkü c'yi içeren hiçbir hiza eşleşemez.
Adım Adım Çalıştırma · Boyer-Moore
Soru 10: boyerMoore İzleme
boyerMoore("KARTAL KALKAR", "KALKAR") hangi değeri döndürür?
n = 13, m = 6. Son görülme: K = 3, A = 4, L = 2, R = 5, diğerleri −1. Karşılaştırma sağdan sola yapılacak.
s = 0: p[5] = 'R' ≠ t[5] = 'L'. Kötü karakter: 'L'.
son['L'] = 2 → max(1, 5 − 2) = 3; s = 3.
s = 3: p[5] = 'R' ≠ t[8] = 'A'. Kötü karakter: 'A'.
son['A'] = 4 → max(1, 5 − 4) = 1; s = 4.
s = 4: p[5] = 'R' ≠ t[9] = 'L'. Kötü karakter: 'L'.
son['L'] = 2 → max(1, 5 − 2) = 3; s = 7.
s = 7: R, A, K, L, A, K sağdan sola eşleşti, j = −1.
j < 0 → 7 döndürülür. 4 hiza, toplam 9 karşılaştırma (kaba kuvvet 8 hiza dener).
int boyerMoore(String t, String p) { int n = t.length(), m = p.length(); int[] son = sonGorulme(p); int s = 0; while (s <= n - m) { int j = m - 1; while (j >= 0 && p.charAt(j) == t.charAt(s + j)) j--; if (j < 0) return s; s += Math.max(1, j - son[t.charAt(s + j)]); } return -1; }
Çıktı Sorusu · Boyer-Moore
Soru 11: Horspool Kaydırma Tablosu
"BARBER" örüntüsü için Horspool kaydırma tablosunu kayd[c] = m − 1 − (c'nin P[0..m−2] içindeki en sağ konumu), yoksa m kuralıyla kurun. Hizanın son karakterinin altındaki metin karakteri B, R ve X olursa örüntü kaçar kaydırılır?
Cevabı göster
m = 6; tabloya yalnızca P[0..4] = B A R B E katılır:
| c | B | A | R | E | diğer |
|---|---|---|---|---|---|
| kayd[c] | 5 − 3 = 2 | 5 − 1 = 4 | 5 − 2 = 3 | 5 − 4 = 1 | 6 |
B → 2, R → 3, X → 6. Son karakter (R, indis 5) tabloya katılmaz; R yine de indis 2'de geçtiği için 3 kaydırır. Kaydırma, uyuşmazlığın nerede olduğuna bakmaz; hep hizanın son karakterine göre yapılır.
Çıktı Sorusu · Rabin-Karp
Soru 12: Kayan Hash
Taban B = 10, Q = 11, karakterler rakam; T = "26535", m = 3. h("265") = 265 mod 11 = 1 ve Bm−1 mod Q = 100 mod 11 = 1'dir. Kaydırma formülü hs+1 = (B · (hs − t[s] · Bm−1) + t[s+m]) mod Q ile h("653") ve h("535")'i bulun.
Cevabı göster
- h("653") = (10 · (1 − 2 · 1) + 3) mod 11 = (−7) mod 11 = 4 ✓ (653 = 59 · 11 + 4)
- h("535") = (10 · (4 − 6 · 1) + 5) mod 11 = (−15) mod 11 = 7 ✓ (535 = 48 · 11 + 7)
Her yeni pencere O(1)'de: çıkan rakam düşülür, kalanlar bir basamak sola kayar, giren rakam eklenir. Ara sonuç negatif çıkabilir; Java'da % negatif verdiği için if (th < 0) th += Q gerekir.
Çoktan Seçmeli · Rabin-Karp
Soru 13: Sahte Eşleşme
Oyuncak hash: harf değerlerinin toplamı (a = 1, b = 2, c = 3, d = 4). "adcb" metninde "bc" (hash 5) aranıyor. Hangi pencereler sahte eşleşme (spurious hit) olur?
D: Pencereler "ad" = 5, "dc" = 7, "cb" = 5. İki pencerenin hash'i örüntününkine eşittir ama karakterleri farklıdır; doğrulama ikisini de reddeder ve metinde "bc" yoktur. Toplam hash sıraya duyarsızdır ("cb" de 5 verir); bu yüzden konum ağırlıklı polinom hash kullanılır.
Çoktan Seçmeli · Rabin-Karp
Soru 14: Çok Sayıda Örüntü
Aynı uzunlukta 500 farklı virüs imzası bir dosyada tek geçişte aranacak. Hangi yaklaşım en uygundur?
B: Pencere hash'i O(1)'de güncellenir ve HashSet'te O(1) ortalamayla aranır; bulunursa doğrulanır → beklenen O(n + k · m). A ve D dosyayı k kez tarar; C ise imzaları birleştirince hiçbir imzayı tek başına bulmaz.
Çoktan Seçmeli · RLE
Soru 15: RLE Ne Zaman Büyütür?
rleSikistir aşağıdaki girdilerden hangisinin çıktısını girdiden uzun yapar?
D: Hiç ardışık tekrar yok; her karakter "1" + karakter olarak yazılır: 8 → 16 karakter (iki kat). Diğerleri küçülür: "5a5b" (10 → 4), "4a1b4a" (9 → 6), "11x1y" (12 → 5). RLE yalnızca ardışık tekrarı yakalar; "abab…" gibi tekrar eden dizgileri LZW yakalar.
Adım Adım Çalıştırma · LZW
Soru 16: lzw İzleme
Başlangıç sözlüğü A = 0, B = 1 iken lzw("BABAABAAA") hangi kodları üretir?
Sözlük tek karakterlerle başlar: A = 0, B = 1; yeni dizgiler 2'den numaralanır. w = "".
"B" sözlükte (1) → w = "B"; daha uzun eşleşme aranır.
"BA" yok → w = "B" kodu 1 çıktıya; "BA" = 2 eklenir; w = "A".
"AB" yok → w = "A" kodu 0 çıktıya; "AB" = 3 eklenir; w = "B".
"BA" sözlükte (2) → w = "BA"; daha uzun eşleşme aranır.
"BAA" yok → w = "BA" kodu 2 çıktıya; "BAA" = 4 eklenir; w = "A".
"AB" sözlükte (3) → w = "AB"; daha uzun eşleşme aranır.
"ABA" yok → w = "AB" kodu 3 çıktıya; "ABA" = 5 eklenir; w = "A".
"AA" yok → w = "A" kodu 0 çıktıya; "AA" = 6 eklenir; w = "A".
"AA" sözlükte (6) → w = "AA"; daha uzun eşleşme aranır.
Döngü bitti; kalan w = "AA" kodu 6 eklenir. Çıktı: 1 0 2 3 0 6 (9 sembol → 6 kod).
List<Integer> lzw(String s) {
Map<String, Integer> sozluk = ilkSozluk(s);
String w = "";
List<Integer> kod = new ArrayList<>();
for (char c : s.toCharArray()) {
String wc = w + c;
if (sozluk.containsKey(wc)) {
w = wc;
} else {
kod.add(sozluk.get(w));
sozluk.put(wc, sozluk.size());
w = "" + c;
}
}
if (!w.isEmpty()) kod.add(sozluk.get(w));
return kod;
}Çıktı Sorusu · LZW
Soru 17: LZW Açma
Başlangıç sözlüğü A = 0, B = 1, C = 2. LZW ile sıkıştırılmış 0 1 3 2 4 7 kod dizisini açın. Hangi kodda açıcı "henüz tanımlanmamış kod" durumuyla karşılaşır?
Cevabı göster
| kod | yazılan | sözlüğe eklenen |
|---|---|---|
| 0 | A | — |
| 1 | B | 3 = AB |
| 3 | AB | 4 = BA |
| 2 | C | 5 = ABC |
| 4 | BA | 6 = CB |
| 7 | BAB | 7 = BAB (özel durum) |
Sonuç: ABABCBABAB. 7 okunduğunda açıcının sözlüğü 6'ya kadardır: e = w + w[0] = "BA" + "B" = "BAB". Kontrol: lzw("ABABCBABAB") yine 0 1 3 2 4 7 verir.
Çoktan Seçmeli · LZW
Soru 18: LZ78 Çıktısı
Sözlüğü boş başlayan LZ78, "abababa" dizgisini hangi (indis, karakter) çiftlerine dönüştürür?
C: "a" → (0, a), sözlüğe 1 = a; "b" → (0, b), 2 = b; "ab": a var (1), ab yok → (1, b), 3 = ab; "aba": ab var (3), aba yok → (3, a), 4 = aba. LZW'nin farkı sözlüğü tüm tek karakterlerle başlatmasıdır; böylece çıktıda karakter yazmaya gerek kalmaz.
Klasik Soru · Karşılaştırma
Soru 19: Senaryoya Göre Algoritma
Her senaryo için dersteki dizgi eşleştirme algoritmalarından birini seçin ve gerekçesini yazın:
(a) Ağdan akan ve geri okunamayan veride, en kötü durumu sınırlı bir arama gerekiyor.
(b) Bir editörde uzun bir İngilizce metinde 12 harfli bir kelime aranıyor.
(c) Bir belgede aynı uzunlukta binlerce cümle (intihal kontrolü) aranıyor.
Cevabı göster
- (a) KMP: metin işaretçisi asla geri gitmez (akışa uygun); en kötü durumda da O(n + m).
- (b) Boyer-Moore / Horspool: uzun örüntü ve geniş alfabede kötü karakter kuralı neredeyse m karakter atlar; pratikte en hızlısı, en iyi O(n/m).
- (c) Rabin-Karp: örüntü hash'leri bir kümeye konur, her pencere O(1)'de güncellenip kümede aranır; beklenen O(n + k · m).
Kaba kuvvet ön işleme istemez ve kısa örüntüde yeterlidir, ama en kötü durumu O(n · m)'dir.