Bölüm 5: Dizgi Algoritmaları (2)
Giriş
Öğrenme Çıktıları
Dizgileri sözlüksel sırayla karşılaştırmak; LSD ve MSD radix sıralamayı adım adım uygulamak ve O(W · (N + R)) maliyetini açıklamak.
Düzenli ifadeler yazıp okumak; bir sonlu durum makinesini (DFA) tasarlamak, çizmek ve bir girdi üzerinde çalıştırmak.
Levenshtein mesafesini ve en uzun ortak alt diziyi (LCS) dinamik programlama tablosuyla hesaplamak ve geri izlemek.
Sonek dizisini kurmak ve aramada kullanmak; Burrows–Wheeler dönüşümünü hesaplamak ve tersine çevirmek.
Giriş
Dizgi Algoritmaları: Dört Problem Ailesi
Bu sunum, dizgiler (string) üzerinde çalışan dört algoritma ailesini ele alır:
Dizgi Sıralama
Sözlüksel Sıralama (Lexicographic Order)
- Sözlüksel (alfabetik) sıralama (lexicographic order), öğeleri karakterlerin alfabedeki ya da kod tablosundaki konumlarına göre dizer.
- Karşılaştırma ilk karakterlerle başlar; eşitse bir sonraki karakterlere bakılır.
- İlk farklı karakter sonucu belirler: "apple" < "banana", çünkü 'a' < 'b'.
- Bir dizgi tükenirse kısa olan (önek) önce gelir: "car" < "cart".
| Karşılaştırma | Karar veren |
|---|---|
| apple · banana | a < b (1. karakter) |
| apple · apricot | p < r (3. karakter) |
| car · cart | "car" tükendi |
| Zebra · apple | 'Z' (90) < 'a' (97) |
java.text.Collator kullanılır.Dizgi Sıralama · Kodu adım adım çalıştır
Örnek: "apple" ve "apricot" Karşılaştırması
karsilastir("apple", "apricot") çağrıldı. Sonuç negatifse a önce, pozitifse b önce gelir (String.compareTo da böyle çalışır).
Kısa olanın uzunluğu kadar karakter karşılaştırılabilir: n = min(5, 7) = 5.
k = 0 < n: döngü sürer; 1. karakterlere bakılacak.
x = 'a' (97), y = 'a' (97) okundu.
'a' == 'a': karakterler eşit, karar verilemez; sonraki karaktere geçilir.
k = 1 < n: döngü sürer; 2. karakterlere bakılacak.
x = 'p' (112), y = 'p' (112) okundu.
'p' == 'p': karakterler eşit, karar verilemez; sonraki karaktere geçilir.
k = 2 < n: döngü sürer; 3. karakterlere bakılacak.
x = 'p' (112), y = 'r' (114) okundu.
'p' ≠ 'r': ilk farklı karakter bulundu (3. karakter).
return 112 − 114 = −2 < 0 → apple, apricot'tan önce gelir. Kalan karakterlere hiç bakılmaz.
int karsilastir(String a, String b) { int n = Math.min(a.length(), b.length()); for (int k = 0; k < n; k++) { char x = a.charAt(k), y = b.charAt(k); if (x != y) return x - y; // ilk farklı karakter } return a.length() - b.length(); }
Dizgi Sıralama
Sözlüksel Sıra: Kelimeler ve Sayılar
- Sayılar dizgi olarak sıralanırsa soldan sağa karakter karşılaştırılır: "11" < "2", çünkü '1' < '2'. Benzer şekilde 123, 45, 6, 789 sözlüksel olarak bu sıradadır.
- Sayısal sıra isteniyorsa sayılar tamsayıya çevrilmeli ya da soldan sıfırla aynı uzunluğa getirilmelidir ("02" < "11").
Dizgi Sıralama
Karşılaştırmalı Dizgi Sıralama
void sozlukselSirala(String[] a) { int n = a.length; for (int i = 0; i < n - 1; i++) for (int j = i + 1; j < n; j++) if (a[i].compareTo(a[j]) > 0) { String gecici = a[i]; a[i] = a[j]; a[j] = gecici; } }
- Her konuma, kalanların sözlükçe en küçüğü yer değiştirmelerle getirilir.
compareToen fazla W karakter okur (W: en uzun dizgi).- Zaman: O(N²) karşılaştırma × O(W) = O(N² · W).
- Birleştirme sıralaması ile O(N log N) karşılaştırma → O(W · N log N).
| Girdi | Çıktı |
|---|---|
| eabcdf, abcde, bcdea, cdeab, deabcg | abcde, bcdea, cdeab, deabcg, eabcdf |
| banana, orange, grape, apple, kiwi | apple, banana, grape, kiwi, orange |
Karşılaştırmalı sıralamalar en az Ω(N log N) karşılaştırma yapar. Radix sıralama karşılaştırma yapmadığı için bu alt sınıra tabi değildir.
Dizgi Sıralama
Tabana Göre Sıralama (Radix Sort)
- Tabana göre sıralama (radix sort), karşılaştırmalı olmayan bir sıralama algoritmasıdır.
- Anahtarlar basamaklara ayrılır: tamsayıda rakamlar, dizgide karakterler.
- Her geçişte, aynı konumda aynı değeri taşıyan öğeler aynı kovaya (bucket) konur.
- Her basamak için ayrı bir geçiş yapılır; geçişin kendisi kararlı (stable) bir sayarak sıralamadır (counting sort).
Dizgi Sıralama · Adım adım
LSD Radix Sıralama: Sayısal Örnek
Veri kümesi: [170, 45, 75, 90, 802, 24, 2, 66]. Kısa sayılar soldan 0 ile tamamlanmış gibi düşünülür (soluk rakamlar).
1. geçiş (birler basamağı): anahtarlar (0, 5, 5, 0, 2, 4, 2, 6) → [170, 90, 802, 2, 24, 45, 75, 66]. Eşit anahtarlar (170, 90) giriş sırasını korur.
2. geçiş (onlar basamağı): anahtarlar (7, 9, 0, 0, 2, 4, 7, 6) → [802, 2, 24, 45, 66, 170, 75, 90].
3. geçiş (yüzler basamağı): anahtarlar (8, 0, 0, 0, 0, 1, 0, 0) → [2, 24, 45, 66, 75, 90, 170, 802]. Dizi sıralandı.
Dizgi Sıralama
LSD Radix: Kararlılık Neden Gerekli?
- Yeşil sütunlar, o ana kadar sıralı hâle gelen son eklerdir: k geçişten sonra dizi, son k basamağa göre sıralıdır.
- 2. geçişte 167 ile 467'nin onlar basamağı eşittir (6); 1. geçişten gelen sıra (7 = 7, giriş sırası) korunur.
- Alt sıralama kararsız olsaydı, örneğin 273 ile 276 son geçişte yer değiştirebilir ve sonuç bozulurdu.
Dizgi Sıralama · Adım adım
LSD Radix Sıralama: Dizgiler
Simülatördeki örnek: cab, dab, bad, dad, fad, ace, bee, bed, add, ebb (W = 3, sağdan sola 3 geçiş).
1. geçiş (3. karakter): son karaktere göre kovalara dağıtılır; aynı kovadakiler (cab, dab) giriş sırasını korur.
2. geçiş (2. karakter): ortanca karaktere göre; 'a' kovasında cab, dab, bad, dad, fad önceki sırayla (b < d) kalır.
3. geçiş (1. karakter): ilk karaktere göre; artık dizi sözlüksel olarak sıralıdır: ace, add, bad, bed, bee, cab, dab, dad, ebb, fad.
Dizgi Sıralama
LSD Radix Sıralama: Java Kodu
void radixSirala(String[] a) { int W = enUzun(a); // en uzun dizgi for (int d = W - 1; d >= 0; d--) sayarakSirala(a, d); // sağdan sola } void sayarakSirala(String[] a, int d) { int[] say = new int[256]; // ASCII for (String s : a) say[kar(s, d)]++; for (int r = 1; r < 256; r++) say[r] += say[r - 1]; String[] gec = new String[a.length]; for (int i = a.length - 1; i >= 0; i--) // kararlı gec[--say[kar(a[i], d)]] = a[i]; System.arraycopy(gec, 0, a, 0, a.length); } int kar(String s, int d) { // kısa dizgi → 0 return d < s.length() ? s.charAt(d) : 0; }
- Sayma: d. karakteri c olan dizgi sayısı
say[c]. - Önek toplamı:
say[c]artık c kovasının bittiği konumu gösterir. - Yerleştirme sondan başa yapılır; böylece eşit anahtarlar aynı sırada kalır (kararlılık).
- Uzunluğu yetmeyen dizgi için
kar0 döndürür: "car", "cart"tan önce gelir.
Bir geçiş O(N + R), R = 256 alfabe boyutu; W geçiş → O(W · (N + R)).
Dizgi Sıralama
MSD Radix Sıralama: Soldan Sağa
- Tüm dizgiler ilk karaktere göre kovalara ayrılır (B, C, M, W).
- Her kova, bir sonraki karaktere göre ayrı ayrı, özyinelemeli sıralanır.
- Tek elemanlı kovada ya da dizgi sonunda (
\0) durulur.
Uzun ortak önekli dizgilerde MSD de tüm karakterleri okur. Küçük kovalarda R = 256 boyutlu sayma dizisi pahalı olduğundan pratikte küçük alt dizilere eklemeli sıralama uygulanır.
Dizgi Sıralama
Zaman Karmaşıklığı ve Karşılaştırma
- LSD: W geçiş (W: en uzun dizginin uzunluğu), her geçiş N dizgi + R kova → O(W · (N + R)).
- Alfabe sabitse (R = 256) maliyet O(W · N) olur: en uzun dizginin uzunluğu × eleman sayısı.
| Yöntem | Zaman | Ek bellek | Kararlı |
|---|---|---|---|
| Yer değiştirmeli sıralama + compareTo | O(N² · W) | O(1) | hayır |
| Birleştirme sıralaması + compareTo | O(W · N log N) | O(N) | evet |
| LSD radix | O(W · (N + R)) | O(N + R) | evet |
| MSD radix | O(N · W) en kötü | O(N + W · R) | evet |
Düzenli İfadeler
Düzenli İfadeler (Regular Expressions)
- Düzenli ifade (regular expression, regex): bir arama örüntüsünü tanımlayan karakter dizisidir.
- Metinde örüntüye uyan tüm parçaları bulmak, doğrulamak, ayıklamak ya da değiştirmek için kullanılır.
- Metin işleme işlerini otomatikleştirir: günlük (log) analizi, form doğrulama, veri temizleme, derleyicilerde sözcük çözümleme (lexer).
- Kuramsal temeli: her düzenli ifadeye eşdeğer bir sonlu durum makinesi vardır (Kleene teoremi).
| Örüntü | Metin | Eşleşmeler |
|---|---|---|
colou?r | color colour | color, colour |
gr(a|e)y | gray grey groy | gray, grey |
\d+ | 20.99 TL, 5 adet | 20, 99, 5 |
\bkod\b | kod kodlama | yalnızca "kod" |
java.util.regex (Pattern, Matcher) ve String.matches, replaceAll, split. Java dizgisinde ters bölü iki kez yazılır: "\\d+".Düzenli İfadeler
Temel Operatörler ve Kavramlar
| Op. | Anlamı | Örnek | İçinde bulunur | Bulunmaz |
|---|---|---|---|---|
. | Herhangi bir tek karakter (yeni satır hariç) | a.c | abc, a7c | ac |
* | Önceki öğenin 0 ya da daha fazla tekrarı | ab*c | ac, abbc | adc |
+ | Önceki öğenin 1 ya da daha fazla tekrarı | ab+c | abc, abbc | ac |
? | Önceki öğenin 0 ya da 1 kez geçmesi | ab?c | ac, abc | abbc |
[ ] | Kümedeki karakterlerden biri | [ck]ar | car, kar | bar |
^ | Dizginin başı | ^ab | abc | cab |
$ | Dizginin sonu | ab$ | cab | abc |
( ) | Gruplama; alt ifade tanımlar | ^(ab)+$ | ab, abab | aba |
Sütunlar, dizginin içinde örüntüye uyan bir parça bulunup bulunmadığını gösterir (Matcher.find). *, +, ? yalnızca hemen önlerindeki öğeye (karakter, küme ya da grup) uygulanır.
Düzenli İfadeler
Karmaşık Operatörler ve Özel Karakterler
| İfade | Anlamı |
|---|---|
a | tek bir 'a' karakteri |
abc | tam olarak "abc" |
{ } | belirli sayıda tekrar: \d{4} |
| | seçenekler: kedi|köpek |
\b | kelime sınırı (başı ya da sonu) |
\d | bir rakam: [0-9] |
\w | bir kelime karakteri: [a-zA-Z0-9_] |
\s | boşluk karakteri: boşluk, tab, yeni satır |
- Büyük harfli biçimler tümleyendir:
\Drakam olmayan,\Wkelime karakteri olmayan,\Sboşluk olmayan karakter. - Özel karakterin kendisi için kaçış gerekir:
\.nokta,\+artı,\(parantez. \wtek bir karakterle eşleşir; bir kelime için\w+yazılır.
\w varsayılan olarak yalnızca ASCII harfleri kapsar: "şeker" içindeki 'ş' eşleşmez. Türkçe için \p{L} ya da Pattern.UNICODE_CHARACTER_CLASS kullanılır.Düzenli İfadeler
Karakter Sınıfları
[abc] | 'a', 'b' ya da 'c' |
[a-z] | herhangi bir küçük harf |
[A-Z] | herhangi bir büyük harf |
[0-9] | herhangi bir rakam |
[a-zA-Z_] | harf ya da alt çizgi |
[^abc] | 'a', 'b', 'c' dışındaki karakter |
[^0-9] | rakam olmayan karakter |
[^0-9]+ | "ab12cd" → "ab", "cd" |
^köşeli parantezin içinde ve başında "değil" anlamına gelir; dışarıda dizginin başıdır.- Küme içinde
.,*,+özel değildir:[.+]nokta ya da artı ile eşleşir. Tire (-) aralık bildirir; kendisi için başa ya da sona yazılır. [a-z]aralığı karakter kodlarına dayanır; ç, ğ, ı, ö, ş, ü bu aralıkta değildir.
Düzenli İfadeler
Yinelenen Karakterler ve Gruplama
Niceleyiciler (quantifiers)
a* | sıfır ya da daha fazla 'a' |
a+ | bir ya da daha fazla 'a' |
a? | sıfır ya da bir 'a' |
a{3} | tam olarak üç 'a' |
a{2,4} | iki ile dört arası 'a' |
a{2,} | en az iki 'a' |
Gruplama
(abc) | tam olarak "abc"; grup olarak yakalanır |
(a|b|c) | 'a', 'b' ya da 'c'; grup olarak yakalanır |
(ab)+ | "ab", "abab", … |
Yakalanan grup Java'da m.group(1) ile okunur.
a{2,4}, "aaaaa" içinde mümkün olan en uzun parçayı (aaaa) alır. Niceleyiciden sonra ? yazılırsa en kısa eşleşme seçilir: "<.+?>", "<b>x</b>" içinde yalnızca "<b>" ile eşleşir.Düzenli İfadeler
İleri ve Geri Bakış (Lookahead, Lookbehind)
| Örüntü | Adı | Eşleşme koşulu | "ab ac ba" |
|---|---|---|---|
a(?=b) | ileri bakış (lookahead) | 'a', ardından 'b' geliyorsa | ab ac ba |
a(?!b) | olumsuz ileri bakış | 'a', ardından 'b' gelmiyorsa | ab ac ba |
(?<=b)a | geri bakış (lookbehind) | 'a', önünde 'b' varsa | ab ac ba |
(?<!b)a | olumsuz geri bakış | 'a', önünde 'b' yoksa | ab ac ba |
- Bakış ifadeleri bir konumu sınar, karakter tüketmez:
a(?=b)eşleşmesi yalnızca "a"dır, 'b' eşleşmeye dahil olmaz. - Örnek:
^(?=.*\d)(?=.*[A-Z]).{8,}$en az bir rakam ve bir büyük harf içeren, en az 8 karakterlik parolayı doğrular.
Düzenli İfadeler
Örnek: Doğrulama İfadeleri
| Amaç | Düzenli ifade |
|---|---|
| E-posta | ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ |
| Telefon | ^(\+\d{1,3}[- ]?)?\d{10}$ |
| URL | ^https?:\/\/[^\s/$.?#].[^\s]*$ |
[…]+ kullanıcı adı, @, alan adı, \. gerçek nokta, en az 2 harfli uzantı. ✓ ali.veli@giresun.edu.tr ✗ ali@tr ✗ a b@x.com(…)? ülke kodu: + ve 1–3 rakam, ardından tire ya da boşluk; sonra tam 10 rakam. ✓ +90 5321234567 ✓ 5321234567 ✗ 0532 123 45 67s? http ya da https; ilk karakter boşluk, /, $, ., ?, # olamaz; sonra boşluksuz karakterler. ✓ https://giresun.edu.tr ✗ ftp://x.com ✗ "http:// x"Bu ifadeler pratik yaklaşımlardır; standartların (RFC 5322 e-posta, RFC 3986 URI) tamamını kapsamaz.
Düzenli İfadeler
Ayrıştırma Ağacı: URL Örneği
http://didit.csail.mit.edu:4949/ için dilbilgisi (grammar):
url ::= 'http://' sunucu
':' port '/'
sunucu ::= kelime '.' sunucu
| kelime
kelime ::= [a-z]+
port ::= [0-9]+http://([a-z]+\.)*[a-z]+:[0-9]+/. Dengeli parantez gibi iç içe yapılar ise düzenli ifadeyle tanımlanamaz; bağlamdan bağımsız dilbilgisi ve ayrıştırıcı (parser) gerekir.Düzenli İfadeler
Java'da Düzenli İfadeler: Pattern ve Matcher
String girdi = "Ad: Ali Veli, Yaş: 30, E-posta: ali.veli@ornek.com";
Pattern p = Pattern.compile("Yaş: (\\d+),"); // derle
Matcher m = p.matcher(girdi);
if (m.find()) { // ilk eşleşmeyi bul
int yas = Integer.parseInt(m.group(1)); // 1. grup: "30"
System.out.println("Yaş: " + yas);
}| Örüntü | group(1) | Açıklama |
|---|---|---|
Ad: (.*?), | Ali Veli | tembel .*?: ilk virgülde durur |
Yaş: (\d+), | 30 | bir ya da daha çok rakam |
E-posta: (.*?)$ | ali.veli@ornek.com | satır sonuna kadar |
- Aynı iş düzenli ifade kullanmadan,
indexOfvesubstringile de yapılabilir: başlangıç işareti (ör. "Yaş: ") bulunur, bitiş işaretine (",") kadar kesilir. find()metnin bir parçasını,matches()tamamını eşleştirmeye çalışır.
Düzenli İfadeler
Deneyin: Düzenli İfade Sınayıcı
Tarayıcının JavaScript düzenli ifade motoru kullanılır; söz dizimi Java ile büyük ölçüde aynıdır. Eşleşmeler vurgulanır, gruplar listelenir.
Sonlu Durum Makineleri
Sonlu Durum Makineleri (Finite State Machines)
- Sonlu durum makinesi (finite state machine, FSM): bir dizgiyi karakter karakter işleyen matematiksel model.
- Sonlu sayıda durumu vardır; bellek yalnızca şu anki durumdur.
- Basit ve anlaşılması kolaydır, yine de karmaşık dizgi analizi problemlerini (sözcük çözümleme, protokol, örüntü arama) ele alabilir.
Sonlu Durum Makineleri
FSM Türleri: DFA, NFA, ε-NFA
- Üçü de aynı dilleri (düzenli diller) tanır: her NFA, alt küme kurulumu (subset construction) ile bir DFA'ya çevrilir; ancak durum sayısı en kötü 2ⁿ'e çıkabilir.
- grep, lex/flex ve derleyici sözcük çözümleyicileri bu zinciri kullanır.
Sonlu Durum Makineleri
Kullanımı: DFA Simülasyonu
- Başlangıç durumuna geç.
- Her karakter için durumu geçiş tablosundan güncelle.
- Dizgi bitince son durumun kabul durumu olup olmadığını denetle.
boolean kabulEder(int[][] gecis, boolean[] kabul, String s) { int durum = 0; // başlangıç durumu for (char c : s.toCharArray()) durum = gecis[durum][c - '0']; // tek geçiş return kabul[durum]; // son durum kabul mü? }
int[|Q|][|Σ|] boyutundadır. Her karakter için bir tablo okuması yapılır: n uzunluklu dizgi O(n) zamanda, geri dönmeden (backtracking olmadan) işlenir.Sonlu Durum Makineleri
Örnek: "nice" Kelimesini Tanıyan Makine
- "nice" kelimesini tanıyan makine: her durum, şimdiye kadar okunan öneki temsil eder (ε, n, ni, nic, nice).
- Beklenen karakter gelmezse (≠n, ≠i, …) Hata durumuna gidilir ve orada kalınır (tuzak durum, trap state).
- "nice" → 1 → 2 → 3 → 4 → 7: kabul. "nine" → 1 → 2 → 3 → 6: ret (üçüncü karakter 'n' ≠ 'c').
Sonlu Durum Makineleri · Adım adım
Örnek: İkili Alfabe Üzerinde DFA
Başlangıç: durum A. Girdi: 10011.
1. sembol 1: δ(A, 1) = B.
2. sembol 0: δ(B, 0) = B.
3. sembol 0: δ(B, 0) = B.
4. sembol 1: δ(B, 1) = C.
5. sembol 1: δ(C, 1) = D. Girdi bitti; D kabul durumu → kabul.
| δ | 0 | 1 |
|---|---|---|
| → A | E | B |
| B | B | C |
| C | B | D |
| D * | D | A |
| E | E | F |
| F | F | A |
→ başlangıç, * kabul. Her hücrede tek durum: DFA.
Sonlu Durum Makineleri
Örnek: "ACACAGA" Örüntüsünü Arayan Otomat
| metin | G | A | C | A | C | A | C | A | G | A |
|---|---|---|---|---|---|---|---|---|---|---|
| durum | 0 | 1 | 2 | 3 | 4 | 5 | 4 | 5 | 6 | 7 |
- Durum q = metnin sonunda örüntüyle uyuşan en uzun önekin uzunluğu. Çizilmeyen tüm geçişler 0'a gider. Durum 7'ye ulaşınca eşleşme bulunur (burada konum 3'te).
- 7. karakter 'C' gelince 5 → 4 dönülür: "ACACAC"nin sonu "ACAC" öneki gibi devam edebilir. Bu, KMP'deki önek fonksiyonunun otomat biçimidir: ön işlem O(m · |Σ|), arama O(n).
Sonlu Durum Makineleri · Kodu adım adım çalıştır
FSM ile Sayı Ayrıştırma: Kodu İzle
Girdi "$20.99 ve 5.". Durum BASLA, tampon boş.
'$' ne rakam ne nokta; durum BASLA, hiçbir şey yapılmaz.
'2' rakam ve durum BASLA → RAKAM; tampona eklendi.
'0' rakam: durum RAKAM kalır, tampona eklenir.
'.' geldi → ONDALIK durumuna geçildi, nokta tampona eklendi.
'9' rakam: durum ONDALIK kalır, tampona eklenir.
'9' rakam: durum ONDALIK kalır, tampona eklenir.
' ' sayı karakteri değil: sayı bitti, 20.99 yazdırıldı; BASLA'ya dönülür.
'v' ne rakam ne nokta; durum BASLA, hiçbir şey yapılmaz.
'e' ne rakam ne nokta; durum BASLA, hiçbir şey yapılmaz.
' ' ne rakam ne nokta; durum BASLA, hiçbir şey yapılmaz.
'5' rakam ve durum BASLA → RAKAM; tampona eklendi.
'.' geldi → ONDALIK durumuna geçildi, nokta tampona eklendi.
Girdi bitti; durum ONDALIK olduğundan tampon yazdırılır: 5.. Sondaki nokta da sayıya katıldı (kusur; bkz. Alıştırmalar).
void sayilariBul(String s) { Durum d = Durum.BASLA; StringBuilder tampon = new StringBuilder(); for (char c : s.toCharArray()) { boolean rakam = Character.isDigit(c); if (rakam) { if (d == Durum.BASLA) d = Durum.RAKAM; tampon.append(c); } else if (c == '.' && d != Durum.ONDALIK) { d = Durum.ONDALIK; tampon.append(c); } else if (d != Durum.BASLA) { // sayı bitti System.out.println(tampon); tampon.setLength(0); d = Durum.BASLA; } } if (d != Durum.BASLA) System.out.println(tampon); }
Düzenleme Mesafesi
Levenshtein Mesafesi (Edit Distance)
- Levenshtein mesafesi (V. Levenshtein, 1965): iki dizgi arasındaki farkı nicel olarak ölçen bir metriktir.
- Bir dizgiyi diğerine dönüştürmek için gereken en az tek karakterlik düzenleme sayısıdır.
- Otomatik düzeltme ve tahmin sistemlerinde, yazım denetiminde, DNA dizilerini karşılaştırmada, bulanık (fuzzy) aramada kullanılır.
- Metrik özellikleri: d(a, a) = 0, d(a, b) = d(b, a), üçgen eşitsizliği.
Düzenleme Mesafesi
Düzenleme Örnekleri
HONDA → HYUNDAI: O→Y değiştir, U ekle, I ekle: d = 3
değiştirme ekleme silme
- (a) rain → sain → shin → shine · (b) shine → rhine → raine → rain (e silinir) · (c) shine → tshine → trhine → traine → train (e silinir). Üstü çizili turuncu harf silinir.
- Mesafe simetriktir: (a) ile (b) birbirinin tersidir; ekleme ↔ silme yer değiştirir.
Düzenleme Mesafesi
Levenshtein Mesafesini Hesaplama
D[i][j] = a'nın ilk i karakterini b'nin ilk j karakterine dönüştürmenin en az maliyeti.
ai = bj ise D[i][j] = D[i−1][j−1]
aksi hâlde D[i][j] = 1 + min( D[i−1][j] silme, D[i][j−1] ekleme, D[i−1][j−1] değiştirme )
- Dinamik programlama: her alt problem bir kez çözülür, (m+1) × (n+1) tabloda saklanır; cevap sağ alt köşededir.
- Bir hücre yalnızca üst, sol ve sol üst komşulara bağlıdır → tablo satır satır doldurulur.
- Zaman O(m · n); bellek O(m · n), yalnızca mesafe gerekiyorsa iki satırla O(min(m, n)).
Düzenleme Mesafesi · Adım adım
DP Tablosu: CARS → PAIRS
a = CARS (satırlar), b = PAIRS (sütunlar)
| ε | P | A | I | R | S | |
|---|---|---|---|---|---|---|
| ε | 0 | 1 | 2 | 3 | 4 | 5 |
| C | 1 | |||||
| A | 2 | |||||
| R | 3 | |||||
| S | 4 |
Başlangıç: ilk satır 0..5 (ε → P, PA, … : ekleme), ilk sütun 0..4 (C, CA, … → ε : silme).
| ε | P | A | I | R | S | |
|---|---|---|---|---|---|---|
| ε | 0 | 1 | 2 | 3 | 4 | 5 |
| C | 1 | 1 | 2 | 3 | 4 | 5 |
| A | 2 | |||||
| R | 3 | |||||
| S | 4 |
1. satır (C) dolduruldu. C ≠ P: D[1][1] = 1 + min(0, 1, 1) = 1 (değiştirme).
| ε | P | A | I | R | S | |
|---|---|---|---|---|---|---|
| ε | 0 | 1 | 2 | 3 | 4 | 5 |
| C | 1 | 1 | 2 | 3 | 4 | 5 |
| A | 2 | 2 | 1 | 2 | 3 | 4 |
| R | 3 | |||||
| S | 4 |
2. satır (A) dolduruldu. A = A: D[2][2] = D[1][1] = 1, maliyet eklenmez.
| ε | P | A | I | R | S | |
|---|---|---|---|---|---|---|
| ε | 0 | 1 | 2 | 3 | 4 | 5 |
| C | 1 | 1 | 2 | 3 | 4 | 5 |
| A | 2 | 2 | 1 | 2 | 3 | 4 |
| R | 3 | 3 | 2 | 2 | 2 | 3 |
| S | 4 |
3. satır (R) dolduruldu. R = R: D[3][4] = D[2][3] = 2. A ≠ I: D[2][3] = 1 + min(1, 2, 3) = 2.
| ε | P | A | I | R | S | |
|---|---|---|---|---|---|---|
| ε | 0 | 1 | 2 | 3 | 4 | 5 |
| C | 1 | 1 | 2 | 3 | 4 | 5 |
| A | 2 | 2 | 1 | 2 | 3 | 4 |
| R | 3 | 3 | 2 | 2 | 2 | 3 |
| S | 4 | 4 | 3 | 3 | 3 | 2 |
4. satır (S) dolduruldu. S = S: D[4][5] = D[3][4] = 2.
| ε | P | A | I | R | S | |
|---|---|---|---|---|---|---|
| ε | 0 | 1 | 2 | 3 | 4 | 5 |
| C | 1 | 1 | 2 | 3 | 4 | 5 |
| A | 2 | 2 | 1 | 2 | 3 | 4 |
| R | 3 | 3 | 2 | 2 | 2 | 3 |
| S | 4 | 4 | 3 | 3 | 3 | 2 |
Sonuç D[4][5] = 2. Geri izleme: C→P değiştir, A eşit, I ekle, R ve S eşit: CARS → PARS → PAIRS.
Düzenleme Mesafesi
Levenshtein: Java Kodu
int levenshtein(String a, String b) { int m = a.length(), n = b.length(); int[][] D = new int[m + 1][n + 1]; for (int i = 0; i <= m; i++) D[i][0] = i; // silme for (int j = 0; j <= n; j++) D[0][j] = j; // ekleme for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) if (a.charAt(i - 1) == b.charAt(j - 1)) D[i][j] = D[i - 1][j - 1]; // eşit else D[i][j] = 1 + Math.min(D[i - 1][j - 1], // değiştir Math.min(D[i][j - 1], // ekle D[i - 1][j])); // sil return D[m][n]; }
- Tablo indisi i, dizgi indisi i − 1'dir: D'nin 0. satırı boş önek içindir.
- Örnekler: kitten → sitting = 3, ercan → sercan = 1, apple → banana = 5.
En Uzun Ortak Alt Dizi
En Uzun Ortak Alt Dizi (LCS)
- En uzun ortak alt dizi (longest common subsequence, LCS): iki dizginin her ikisinde de sıralı olarak bulunan en uzun dizi.
- Karakterlerin ardışık olması gerekmez, ancak göreli sıraları korunmalıdır.
- İki dizgi arasındaki benzerlik seviyesini ölçer:
diff, sürüm kontrolü, DNA hizalama, intihal tespiti.
LCS = GTAB, uzunluk 4
LCS = acad, uzunluk 4 (abad da olur)
En Uzun Ortak Alt Dizi
Dinamik Programlama Yaklaşımı
String lcs(String a, String b) {
int m = a.length(), n = b.length();
int[][] L = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
if (a.charAt(i - 1) == b.charAt(j - 1))
L[i][j] = L[i - 1][j - 1] + 1;
else
L[i][j] = Math.max(L[i - 1][j], L[i][j - 1]);
StringBuilder s = new StringBuilder(); // geri izle
for (int i = m, j = n; i > 0 && j > 0; )
if (a.charAt(i - 1) == b.charAt(j - 1)) {
s.insert(0, a.charAt(i - 1)); i--; j--;
} else if (L[i - 1][j] > L[i][j - 1]) i--;
else j--;
return s.toString();
}- Uzunluklar m ve n; (m+1) × (n+1) tablo.
- İlk satır ve sütun 0.
- A[i] = B[j] ise hücre = sol üst + 1.
- A[i] ≠ B[j] ise hücre = max(üst, sol).
- Son hücre LCS uzunluğudur; dizinin kendisi geri izlemeyle bulunur.
Zaman ve bellek O(m · n); geri izleme O(m + n).
En Uzun Ortak Alt Dizi · Adım adım
LCS Tablosu: AGGTAB · GXTXAYB
A = AGGTAB (satırlar), B = GXTXAYB (sütunlar)
| ε | G | X | T | X | A | Y | B | |
|---|---|---|---|---|---|---|---|---|
| ε | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| A | 0 | |||||||
| G | 0 | |||||||
| G | 0 | |||||||
| T | 0 | |||||||
| A | 0 | |||||||
| B | 0 |
İlk satır ve sütun 0: boş dizginin herhangi bir dizgiyle LCS'si boştur.
| ε | G | X | T | X | A | Y | B | |
|---|---|---|---|---|---|---|---|---|
| ε | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| A | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| G | 0 | |||||||
| G | 0 | |||||||
| T | 0 | |||||||
| A | 0 | |||||||
| B | 0 |
1. satır (A). A yalnızca B[5] = A ile eşleşir: L[1][5] = 0 + 1 = 1; sağa doğru max ile 1 taşınır.
| ε | G | X | T | X | A | Y | B | |
|---|---|---|---|---|---|---|---|---|
| ε | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| A | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| G | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| G | 0 | |||||||
| T | 0 | |||||||
| A | 0 | |||||||
| B | 0 |
2. satır (G). G = G (j = 1): L[2][1] = 1. Satırın geri kalanı max(üst, sol) = 1.
| ε | G | X | T | X | A | Y | B | |
|---|---|---|---|---|---|---|---|---|
| ε | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| A | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| G | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| G | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| T | 0 | |||||||
| A | 0 | |||||||
| B | 0 |
3. satır (G). İkinci G de yalnızca 1 verir: aynı G iki kez kullanılamaz (sol üst = 0).
| ε | G | X | T | X | A | Y | B | |
|---|---|---|---|---|---|---|---|---|
| ε | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| A | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| G | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| G | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| T | 0 | 1 | 1 | 2 | 2 | 2 | 2 | 2 |
| A | 0 | |||||||
| B | 0 |
4. satır (T). T = T (j = 3): L[4][3] = L[3][2] + 1 = 2 → "GT".
| ε | G | X | T | X | A | Y | B | |
|---|---|---|---|---|---|---|---|---|
| ε | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| A | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| G | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| G | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| T | 0 | 1 | 1 | 2 | 2 | 2 | 2 | 2 |
| A | 0 | 1 | 1 | 2 | 2 | 3 | 3 | 3 |
| B | 0 |
5. satır (A). A = A (j = 5): L[5][5] = L[4][4] + 1 = 3 → "GTA".
| ε | G | X | T | X | A | Y | B | |
|---|---|---|---|---|---|---|---|---|
| ε | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| A | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| G | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| G | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| T | 0 | 1 | 1 | 2 | 2 | 2 | 2 | 2 |
| A | 0 | 1 | 1 | 2 | 2 | 3 | 3 | 3 |
| B | 0 | 1 | 1 | 2 | 2 | 3 | 3 | 4 |
6. satır (B). B = B (j = 7): L[6][7] = L[5][6] + 1 = 4 → "GTAB".
| ε | G | X | T | X | A | Y | B | |
|---|---|---|---|---|---|---|---|---|
| ε | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| A | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| G | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| G | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| T | 0 | 1 | 1 | 2 | 2 | 2 | 2 | 2 |
| A | 0 | 1 | 1 | 2 | 2 | 3 | 3 | 3 |
| B | 0 | 1 | 1 | 2 | 2 | 3 | 3 | 4 |
Geri izleme sağ alttan: eşleşmede çapraz (turuncu, karakter LCS'ye eklenir), değilse büyük olan komşuya. Sonuç GTAB, uzunluk 4.
En Uzun Ortak Alt Dizi
Örnek: DNA Dizilerinde LCS
- Eşleşen karakterleri birleştiren çizgiler kesişmez: göreli sıra korunur. Bu kural sağlanan her eşleme bir ortak alt dizidir.
- DP sonucu: LCS = GGAAATTCA, uzunluk 9.
En Uzun Ortak Alt Dizi
Benzerlik Ölçülerinin Karşılaştırılması
| Ölçü | Ne ölçer? | Zaman | AGGTAB · GXTXAYB |
|---|---|---|---|
| Hamming | eşit uzunlukta, farklı konum sayısı | O(n) | tanımsız (6 ≠ 7) |
| Levenshtein | ekle / sil / değiştir sayısı | O(m · n) | 4 |
| LCS | en uzun ortak alt dizi | O(m · n) | 4 (GTAB) |
| En uzun ortak alt dizgi | ardışık ortak parça | O(m · n) | 1 (ör. "G") |
- Yalnızca ekleme ve silmeye izin verilirse mesafe = m + n − 2 · LCS: 6 + 7 − 8 = 5; değiştirmeye de izin veren Levenshtein bunu 4'e indirir.
- En uzun ortak alt dizgi: eşleşmede L[i][j] = L[i−1][j−1] + 1, eşleşmezse 0; cevap tablonun en büyük değeridir (ercan · sercan → "ercan").
- Benzerlik oranı örneği: 1 − d / max(m, n). kitten · sitting: 1 − 3/7 ≈ 0,57.
Dizgi Dönüşümleri
Sonek Dizisi (Suffix Array)
- Sonek dizisi (suffix array): bir dizginin tüm soneklerinin alfabetik sıraya dizilmiş hâlinin başlangıç indisleri.
- Her sonek, dizginin belirli bir konumundan başlayıp sonuna kadar giden alt dizgidir. Sonek dizisi tüm alt dizgilerin sıkı bir temsilidir: her alt dizgi bir sonekin önekidir.
| i | sonek |
|---|---|
| 0 | banana |
| 1 | anana |
| 2 | nana |
| 3 | ana |
| 4 | na |
| 5 | a |
| sıra | SA | sıralı sonek |
|---|---|---|
| 0 | 5 | a |
| 1 | 3 | ana |
| 2 | 1 | anana |
| 3 | 0 | banana |
| 4 | 4 | na |
| 5 | 2 | nana |
"banana" → SA = [5, 3, 1, 0, 4, 2]. Kullanım: dizgi arama, sıralama, genetik dizilim analizi, BWT ve veri sıkıştırma.
Dizgi Dönüşümleri
Sonek Dizisi Oluşturma Yöntemleri
| Yöntem | Fikir | Zaman |
|---|---|---|
| Kaba kuvvet | Tüm sonekleri oluştur, Arrays.sort ile sırala; her karşılaştırma O(n) | O(n² log n) |
| Manber–Myers (1990) | Önek ikiye katlama: k karakterlik sıralardan 2k karakterlik sırayı harf karşılaştırmadan, sıra çiftleriyle radix sıralayarak bulur | O(n log n) |
| Larsson–Sadakane (1999) | Aynı ikiye katlama; yalnızca henüz ayrışmamış gruplar, art arda soneklerin sıraları karşılaştırılarak yeniden sıralanır | O(n log n) |
| DC3 (2003), SA-IS (2009) | Soneklerin bir kısmını özyinelemeli sıralayıp kalanı birleştirir | O(n) |
Dizgi Dönüşümleri · Adım adım
Önek İkiye Katlama (Prefix Doubling)
Manber–Myers fikri, "banana" üzerinde: k karakterlik sıralardan 2k karakterlik sıra elde edilir. log₂ n tur, her tur radix ile O(n).
| i | ilk 1 karakter | anahtar | yeni sıra |
|---|---|---|---|
| 1 | a | 'a' | 0 |
| 3 | a | 'a' | 0 |
| 5 | a | 'a' | 0 |
| 0 | b | 'b' | 1 |
| 2 | n | 'n' | 2 |
| 4 | n | 'n' | 2 |
k = 1: sonekler ilk karakterlerine göre sıralanır: a → 0, b → 1, n → 2. Eşit sıralar henüz ayrışmamıştır.
| i | ilk 2 karakter | anahtar | yeni sıra |
|---|---|---|---|
| 5 | a | (0, −1) | 0 |
| 1 | an | (0, 2) | 1 |
| 3 | an | (0, 2) | 1 |
| 0 | ba | (1, 0) | 2 |
| 2 | na | (2, 0) | 3 |
| 4 | na | (2, 0) | 3 |
k = 2: anahtar = (sıra[i], sıra[i + 1]); i + 1 ≥ n ise −1. Harf karşılaştırılmaz, yalnızca sayı çiftleri sıralanır.
| i | ilk 4 karakter | anahtar | yeni sıra |
|---|---|---|---|
| 5 | a | (0, −1) | 0 |
| 3 | ana | (1, 0) | 1 |
| 1 | anan | (1, 1) | 2 |
| 0 | bana | (2, 3) | 3 |
| 4 | na | (3, −1) | 4 |
| 2 | nana | (3, 3) | 5 |
k = 4: anahtar = (sıra[i], sıra[i + 2]); i + 2 ≥ n ise −1. Harf karşılaştırılmaz, yalnızca sayı çiftleri sıralanır. Tüm sıralar farklı → SA = [5, 3, 1, 0, 4, 2].
Dizgi Dönüşümleri
Sonek Dizisiyle Arama
- Sonekler sıralı olduğundan, P örüntüsüyle başlayan sonekler SA'da bitişik bir aralık oluşturur.
- Aralığın iki ucu ikili arama ile bulunur: O(log n) adım × O(m) karşılaştırma = O(m log n).
- Sonek trie'sine göre çok az bellek: yalnızca n tamsayı.
- LCP dizisi (komşu soneklerin en uzun ortak öneki) eklenirse en uzun tekrar eden alt dizgi O(n)'de bulunur.
| sıra | SA | sonek |
|---|---|---|
| 0 | 5 | a |
| 1 | 3 | ana |
| 2 | 1 | anana |
| 3 | 0 | banana |
| 4 | 4 | na |
| 5 | 2 | nana |
Dizgi Dönüşümleri
Burrows–Wheeler Dönüşümü (BWT)
- Burrows–Wheeler dönüşümü (BWT, 1994): girdiyi yeniden düzenler; karakterleri değiştirmez, yalnızca yerlerini değiştirir.
- Aynı karakterlerin bir araya toplanmasını sağlar: benzer bağlamdan önce gelen karakterler yan yana düşer.
- Sıkıştırma algoritmalarının performansını artırır.
- Tersine çevrilebilir: orijinal veri dönüşümden geri elde edilir.
Uygulama adımları
- Girdi dizgisinin tüm döndürülmüş hâllerini (cyclic rotations) oluştur.
- Döndürmeleri alfabetik olarak sırala.
- Sıralı döndürmelerin son karakterlerinden yeni bir dizgi oluştur (L sütunu).
- Orijinal dizginin sıralı listedeki satır numarasını sakla (ya da sona tekil bir
$ekle).
Dizgi Dönüşümleri · Adım adım
BWT Örneği: BANANA
Girdi: BANANA
1. Tüm döndürmeler: BANANA, ANANAB, NANABA, ANABAN, NABANA, ABANAN (ilk karakter sona taşınarak).
2. Alfabetik sıralama: ABANAN, ANABAN, ANANAB, BANANA, NABANA, NANABA. Orijinal dizgi 3. satırda.
3. Son karakterler (L sütunu): NNBAAA. Çıktı: (NNBAAA, 3). Aynı harfler gruplandı: NN, AAA.
Dizgi Dönüşümleri
BWT Örneği: abraca
- Sıralı matrisin son sütunu: L = caraab.
- Orijinal "abraca" sıralı matriste 1. satırdadır (0'dan sayarak); ters dönüşüm için bu indis saklanır.
- İlk sütun (F = aaabcr), L'nin harflerinin sıralanmış hâlidir; L'yi bilmek F'yi de verir.
substring ile üretip Arrays.sort ile sıralar → O(n² log n) zaman, O(n²) bellek. Pratikte sonek dizisinden L[i] = T[SA[i] − 1] ile O(n)'de elde edilir (T sonuna $ eklenmiş metin).Dizgi Dönüşümleri
BWT'yi Tersine Çevirme (LF Eşlemesi)
| i | F | … | L |
|---|---|---|---|
| 0 | $ | banan | a |
| 1 | a | $bana | n |
| 2 | a | na$ba | n |
| 3 | a | nana$ | b |
| 4 | b | anana | $ |
| 5 | n | a$ban | a |
| 6 | n | ana$b | a |
- T = banana$ ($ en küçük, tekil) → BWT = annb$aa.
- F = sırala(L) = $aaabnn.
- LF kuralı: L'deki k. 'c', F'deki k. 'c' ile aynı karakterdir. i satırındaki L[i], metinde F[i]'den hemen önce gelir.
- $ ile başlayan 0. satırdan başla, L[i]'yi oku, LF(i) satırına git:
okunan L: a n a n a b → ters çevir → banana
Sıra sayıları (her karakterin L'de kaçıncı olduğu) önceden hesaplanırsa ters dönüşüm O(n) zaman alır. $ yoksa, BANANA örneğindeki gibi orijinal satır indisi (3) saklanır.
Özet
Özet
| Konu | Hatırlanacaklar |
|---|---|
| Sözlüksel sıra | ilk farklı karakter karar verir; önek önce gelir; kod sırası ≠ Türkçe alfabe |
| Radix | LSD: sağdan sola kararlı sayarak sıralama, O(W · (N + R)); MSD: soldan, kovalarda özyineleme |
| Düzenli ifade | . * + ? [ ] ^ $ ( ) { } | \d \w \s; bakış ifadeleri karakter tüketmez |
| FSM | (Q, Σ, δ, q₀, F); DFA'da tek geçiş, O(n) tarama; NFA ≡ DFA ≡ düzenli ifade |
| Levenshtein | 1 + min(sil, ekle, değiştir), eşitse sol üst; O(m · n) |
| LCS | eşitse sol üst + 1, değilse max(üst, sol); geri izlemeyle dizi |
| Sonek dizisi | sıralı sonek indisleri; kaba kuvvet O(n² log n), ikiye katlama O(n log n); arama O(m log n) |
| BWT | sıralı döndürmelerin son sütunu + satır indisi; LF eşlemesiyle geri dönüş; bzip2 |
Özet
Etkileşimli Simülatörler
Özet
Sık Yapılan Hatalar
Collator ya da normalleştirme gerekir.a.b "a+b" ile de eşleşir; <.*> tüm satırı yutar. \. ve tembel .*? kullanın. (a+)+$ gibi ifadeler üstel geri izlemeye yol açar.charAt(i − 1) karşılaştırılır. İlk satır/sütunu başlatmamak sonucu bozar.$'ı saklamayı unutmak dönüşümü geri alınamaz kılar.Özet
Örnek Problemler
- "10", "9", "100", "2" dizgilerini sözlüksel sıraya koyun.
- [329, 457, 657, 839, 436, 720, 355] dizisine LSD radix uygulayın; her geçişten sonraki diziyi yazın.
^\d{3}-\d{4}$ifadesi "555-1234", "5551234", "55-12345" dizgilerinden hangileriyle eşleşir?- Levenshtein("sunday", "saturday") kaçtır?
- LCS("ABCBDAB", "BDCABA") uzunluğu kaçtır? Bir LCS yazın.
- "kayak" dizgisinin BWT'sini ve orijinal satır indisini bulun.
Cevapları göster
- "10" < "100" < "2" < "9" ("10", "100"ün önekidir).
- 1: 720, 355, 436, 457, 657, 329, 839 · 2: 720, 329, 436, 839, 355, 457, 657 · 3: 329, 355, 436, 457, 657, 720, 839.
- Yalnızca "555-1234".
- 3: "a" ve "t" ekle (satunday), n → r değiştir (saturday).
- 4; örneğin BCBA (BDAB ve BCAB de olur).
- Sıralı döndürmeler: akkay, ayakk, kayak, kkaya, yakka → BWT = ykkaa, indis 2.
Özet
Alıştırmalar
- MSD radix sıralamayı özyinelemeli olarak yazın.
- Türkiye cep telefonu biçimini (0532 123 45 67) doğrulayan bir düzenli ifade yazın.
- İkili dizgilerde 1 sayısı çift olanları kabul eden bir DFA çizin ve geçiş tablosunu yazın.
- Levenshtein'ı yalnızca iki satırlık bellekle, O(min(m, n)) ek alanla hesaplayın.
- Sayı ayrıştıran FSM "… ve 5." girdisinde "5." yazdırır. Makineyi düzeltin.
- "mississippi" metninin sonek dizisini bulun.
Cevaplar / ipuçları
sirala(a, alt, ust, d): d. karaktere göre kovalara dağıt (sonu biten dizgiler −1 kovası), her kova içinsirala(…, d + 1).^0\d{3} \d{3} \d{2} \d{2}$(yalnızca 05 için:^05\d{2} …).- İki durum: Çift (başlangıç, kabul) ve Tek. 0: aynı durumda kal; 1: Çift ↔ Tek.
oncekivesimdidizileri; her satır sonunda yer değiştirin. Kısa dizgiyi sütun yapın.- Yazdırmadan önce tampon '.' ile bitiyorsa son karakteri silin (ya da noktayı ancak ardından rakam gelirse ekleyin).
- SA = [10, 7, 4, 1, 0, 9, 8, 6, 3, 5, 2] (i, ippi, issippi, ississippi, mississippi, pi, ppi, sippi, sissippi, ssippi, ssissippi).
Özet
Kaynaklar
- Sedgewick ve Wayne, Algorithms, 4. baskı, 2011 (5.1 String Sorts, 5.4 Regular Expressions).
- Cormen, Leiserson, Rivest ve Stein, Introduction to Algorithms, 4. baskı, 2022 (LCS, dizgi eşleme otomatları).
- Hopcroft, Motwani ve Ullman, Introduction to Automata Theory, Languages, and Computation, 3. baskı, 2006.
- V. I. Levenshtein, "Binary codes capable of correcting deletions, insertions, and reversals", Soviet Physics Doklady 10(8), 1966.
- R. A. Wagner ve M. J. Fischer, "The String-to-String Correction Problem", Journal of the ACM 21(1), 1974.
- U. Manber ve G. Myers, "Suffix Arrays: A New Method for On-Line String Searches", SIAM Journal on Computing 22(5), 1993.
- M. Burrows ve D. J. Wheeler, "A Block-sorting Lossless Data Compression Algorithm", DEC SRC Research Report 124, 1994.
- J. E. F. Friedl, Mastering Regular Expressions, 3. baskı, O'Reilly, 2006; Java
java.util.regex.Patternbelgeleri.