Düzenleme Mesafesi (Edit Distance)
Bir kelimeyi diğerine çevirmek için gereken en az harf değiştirme, silme ve ekleme sayısını bulan Levenshtein algoritması.
Önce bunlara göz at
#Nasıl çalışır?
Düzenleme mesafesi (Levenshtein mesafesi), bir kelimeyi diğerine çevirmek için gereken en az tek harflik işlem sayısıdır. İzin verilen işlemler: bir harfi değiştirmek, silmek ya da eklemek. KITTEN → SITTING için mesafe 3'tür: K→S, E→I ve sona G eklemek.
dp[i][j], X'in ilk i harfini Y'nin ilk j harfine çevirmenin en düşük maliyetidir. Son harfler aynıysa işlem gerekmez ve çapraz değer alınır. Farklıysa üç seçenekten en ucuzu seçilir: değiştirmek (çapraz), X'teki harfi silmek (üst) ya da Y'deki harfi eklemek (sol); hepsine 1 eklenir.
Yapısı LCS'e çok benzer; LCS ortak olanı en büyüklerken düzenleme mesafesi farkı en küçükler. Tablonun sağ alttan geri izlenmesi, işlemlerin listesini verir.
#Kendin dene
| S | I | T | T | I | N | G | ||
|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
| K | 1 | |||||||
| I | 2 | |||||||
| T | 3 | |||||||
| T | 4 | |||||||
| E | 5 | |||||||
| N | 6 |
Bir kelimeyi diğerine çevirmek için en az kaç harf değiştirme, silme ya da ekleme gerekir? Hücre, ilk i harfi ilk j harfe çevirmenin en düşük maliyetidir.
#Adım adım
- 01İlk satır dp[0][j] = j (j harf eklemek), ilk sütun dp[i][0] = i (i harf silmek).
- 02Harfler aynıysa dp[i][j] = dp[i − 1][j − 1].
- 03Farklıysa dp[i][j] = 1 + min(çapraz, üst, sol).
- 04dp[m][n] mesafedir; sağ alttan geri izleyerek işlemleri oku.
#Örnek kod
Aynı algoritma 8 dilde. Her program derlenip çalıştırılarak test edildi ve hepsi aynı çıktıyı veriyor.
def edit_distance(x: str, y: str) -> int:
m, n = len(x), len(y)
# dp[i][j] = cheapest way to turn x[:i] into y[:j].
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(m + 1):
dp[i][0] = i # delete everything
for j in range(n + 1):
dp[0][j] = j # insert everything
for i in range(1, m + 1):
for j in range(1, n + 1):
if x[i - 1] == y[j - 1]:
dp[i][j] = dp[i - 1][j - 1] # no edit needed
else:
dp[i][j] = 1 + min(dp[i - 1][j - 1], # replace
dp[i - 1][j], # delete
dp[i][j - 1]) # insert
return dp[m][n]
print(edit_distance("KITTEN", "SITTING")) # K->S, E->I, +G
print(edit_distance("SUNDAY", "SATURDAY"))#Karmaşıklık
| İşlem | Süre |
|---|---|
| Zaman | O(m · n) |
| Bellek (tam tablo) | O(m · n) |
| Sadece mesafe (iki satır) | O(min(m, n)) bellek |
| İşlemleri geri izlemek | O(m + n) |
Her hücre sabit sürede doldurulur. Yalnızca mesafe gerekiyorsa iki satır yeterlidir. Mesafenin küçük bir k değerinden az olup olmadığı soruluyorsa sadece köşegen etrafındaki bant hesaplanarak O(k · n) zamana inilebilir.
#Ne zaman kullanılır?
Yazım denetimi ve "bunu mu demek istediniz?" önerileri, arama motorlarında bulanık eşleştirme, DNA dizilerinin karşılaştırılması, OCR ve konuşma tanıma çıktılarının düzeltilmesi ve diff araçları düzenleme mesafesi kullanır.
#Alıştırma
Soruları cevaplamak ve ilerlemeni kaydetmek için giriş yap.
Kolay
Levenshtein mesafesinde hangi işlemlere izin verilir?
- 1Harf değiştirme, silme ve ekleme
- 2Yalnızca harf değiştirme
- 3Harfleri yer değiştirme ve sıralama
- 4Yalnızca ekleme ve silme
KITTEN ile SITTING arasındaki düzenleme mesafesi kaçtır?
- 13
- 22
- 34
- 47
Tablonun ilk satırı dp[0][j] neden j'dir?
- 1Boş bir kelimeden j harfli kelimeye ancak j ekleme ile gidilir
- 2Harfler eşit olduğu için
- 3j harf silmek gerektiği için
- 4Bu bir varsayımdır, önemi yoktur
Orta
X[i] ≠ Y[j] ise dp[i][j] nasıl hesaplanır?
- 11 + min(dp[i−1][j−1], dp[i−1][j], dp[i][j−1])
- 2max(dp[i−1][j], dp[i][j−1])
- 3dp[i−1][j−1]
- 4dp[i−1][j] + dp[i][j−1]
Zor
Düzenleme mesafesi ile LCS arasındaki ilişki nedir?
- 1Aynı tablo yapısını kullanırlar; biri farkı en küçükler, diğeri ortak olanı en büyükler
- 2Hiçbir ilişkileri yoktur
- 3LCS, düzenleme mesafesinin özel bir hâlidir ve her zaman eşittirler
- 4Düzenleme mesafesi graf algoritmasıdır