Jarak Edit (Levenshtein)
Turunkan relasi rekurensi jarak edit untuk operasi penyisipan/penghapusan/penggantian, lalu isi tabel DP untuk pasangan string dengan panjang beragam.
Jarak Edit (Levenshtein) adalah pelajaran DSA Interview Prep gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar DSA Interview Prep, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus DSA Interview Prep mencakup 4 pelajaran total.
Masalah Jarak Edit
Jarak Edit (jarak Levenshtein, LeetCode 72) menanyakan: berapa jumlah minimum operasi penyisipan, penghapusan, atau penggantian yang diperlukan untuk mengubah satu teks menjadi teks lainnya? Sebagai contoh, untuk mengubah 'horse' menjadi 'ros': ganti 'h'→'r' (horse→rorse), hapus 'r' (rorse→rose), hapus 'e' (rose→ros) — 3 operasi. Jarak edit menjadi dasar bagi pemeriksa ejaan, penyelarasan DNA, dan pencocokan samar.
# Allowed operations:
# Insert: 'abc' → 'abXc' (insert X)
# Delete: 'abc' → 'ac' (delete b)
# Replace: 'abc' → 'aXc' (replace b with X)
# horse → ros: 3 operations
# 1. horse → rorse (replace h with r)
# 2. rorse → rose (delete r at index 1)
# 3. rose → ros (delete e)
print('Edit distance horse→ros: 3')
print('Edit distance intention→execution: 5')Keadaan DP dan Relasi Rekurensi
Definisikan dp[i][j] = jarak edit minimum antara word1[:i] dan word2[:j]. Jika word1[i-1] == word2[j-1], tidak diperlukan operasi: dp[i][j] = dp[i-1][j-1]. Jika tidak, ambil minimum dari tiga operasi: sisipkan dp[i][j-1] + 1, hapus dp[i-1][j] + 1, ganti dp[i-1][j-1] + 1. Kasus dasar: dp[i][0] = i (hapus seluruh teks pertama) dan dp[0][j] = j (sisipkan seluruh teks kedua).
def edit_distance(word1, word2):
m, n = len(word1), len(word2)
dp = [[0]*(n+1) for _ in range(m+1)]
# Base cases
for i in range(m+1): dp[i][0] = i # delete all of word1
for j in range(n+1): dp[0][j] = j # insert all of word2
for i in range(1, m+1):
for j in range(1, n+1):
if word1[i-1] == word2[j-1]:
dp[i][j] = dp[i-1][j-1] # no cost
else:
dp[i][j] = 1 + min(
dp[i][j-1], # insert
dp[i-1][j], # delete
dp[i-1][j-1] # replace
)
return dp[m][n]
print(edit_distance('horse', 'ros')) # 3
print(edit_distance('intention', 'execution')) # 5Memahami Tiga Operasi
Ketiga operasi tersebut secara langsung dipetakan ke perpindahan dalam tabel DP: Ganti dp[i-1][j-1]+1 — kita mencocokkan kedua karakter, tetapi membayar satu biaya. Hapus dari teks pertama dp[i-1][j]+1 — hapus satu karakter dari teks pertama (bergerak ke atas dalam tabel). Sisipkan ke teks pertama dp[i][j-1]+1 — sisipkan satu karakter untuk mencocokkan teks kedua (bergerak ke kiri). Nilai minimum dari ketiganya menghasilkan jalur edit yang optimal.
# Visualise the DP table for 'cat' → 'cut'
# dp[i][j] = min edits for word1[:i] vs word2[:j]
word1, word2 = 'cat', 'cut'
m, n = len(word1), len(word2)
dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(m+1): dp[i][0] = i
for j in range(n+1): dp[0][j] = j
for i in range(1, m+1):
for j in range(1, n+1):
if word1[i-1]==word2[j-1]: dp[i][j]=dp[i-1][j-1]
else: dp[i][j]=1+min(dp[i][j-1],dp[i-1][j],dp[i-1][j-1])
print(' ', ' '.join(' '+word2))
for i, row in enumerate(dp):
print((' ' if i==0 else word1[i-1]), row)Optimasi Ruang menjadi O(n)
Jarak edit hanya memerlukan baris saat ini dan baris sebelumnya. Gunakan larik 1D berukuran n+1 dan lacak nilai diagonal (dp[i-1][j-1]) secara terpisah sebelum setiap pembaruan sel. Proses dari kiri ke kanan: temp = dp[j] (nilai lama = dp[i-1][j]), lalu perbarui dp[j] menggunakan dp[j] (penghapusan), dp[j-1] (penyisipan), dan diagonal (penggantian).
def edit_distance_1d(word1, word2):
m, n = len(word1), len(word2)
dp = list(range(n + 1)) # initial row: 0,1,2,...,n
for i in range(1, m + 1):
diag = dp[0] # dp[i-1][0]
dp[0] = i # dp[i][0] = i
for j in range(1, n + 1):
temp = dp[j] # dp[i-1][j] before overwrite
if word1[i-1] == word2[j-1]:
dp[j] = diag
else:
dp[j] = 1 + min(dp[j], # delete
dp[j-1], # insert
diag) # replace
diag = temp
return dp[n]
print(edit_distance_1d('horse', 'ros')) # 3
print(edit_distance_1d('intention', 'execution')) # 5Merekonstruksi Operasi Edit
Untuk merekonstruksi urutan edit yang sebenarnya, telusuri tabel DP mundur dari (m, n). Pada setiap sel: jika word1[i-1] == word2[j-1], bergeraklah secara diagonal (tanpa operasi). Jika tidak, tentukan tetangga mana dari ketiganya yang menghasilkan nilai minimum dan catat operasi yang sesuai. Proses ini menghasilkan skrip edit secara terbalik; balik urutannya untuk mendapatkan jawaban akhir.
def edit_ops(word1, word2):
m, n = len(word1), len(word2)
dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(m+1): dp[i][0]=i
for j in range(n+1): dp[0][j]=j
for i in range(1,m+1):
for j in range(1,n+1):
if word1[i-1]==word2[j-1]: dp[i][j]=dp[i-1][j-1]
else: dp[i][j]=1+min(dp[i][j-1],dp[i-1][j],dp[i-1][j-1])
ops, i, j = [], m, n
while i>0 or j>0:
if i>0 and j>0 and word1[i-1]==word2[j-1]:
i-=1; j-=1
elif j>0 and (i==0 or dp[i][j-1]<=dp[i-1][j] and dp[i][j-1]<=dp[i-1][j-1]):
ops.append(f'Insert {word2[j-1]} at pos {i}'); j-=1
elif i>0 and (j==0 or dp[i-1][j]<=dp[i][j-1] and dp[i-1][j]<=dp[i-1][j-1]):
ops.append(f'Delete {word1[i-1]} at pos {i-1}'); i-=1
else:
ops.append(f'Replace {word1[i-1]} with {word2[j-1]}'); i-=1; j-=1
return list(reversed(ops))
for op in edit_ops('horse', 'ros'): print(op)Pemeriksaan Jarak Satu Edit
Masalah wawancara yang lebih sederhana: apakah dua teks berjarak tepat satu operasi edit? Masalah ini dapat diselesaikan dalam O(n) tanpa DP. Telusuri kedua teks secara bersamaan. Saat terjadi ketidakcocokan, coba ketiga operasi (lewati satu karakter di s1, lewati satu karakter di s2, lewati keduanya) dan periksa apakah sisa teksnya identik. Jika terjadi dua ketidakcocokan, kembalikan False. Pendekatan rakus ini menghindari DP O(mn) penuh jika Anda hanya perlu mengetahui apakah jaraknya ≤ 1.
def is_one_edit_distance(s, t):
m, n = len(s), len(t)
if abs(m - n) > 1: return False
if m > n: return is_one_edit_distance(t, s) # ensure m <= n
for i in range(m):
if s[i] != t[i]:
if m == n:
return s[i+1:] == t[i+1:] # replace
else:
return s[i:] == t[i+1:] # insert into s (delete from t)
return m + 1 == n # all matched, lengths differ by 1
print(is_one_edit_distance('ab', 'acb')) # True (insert c)
print(is_one_edit_distance('ab', 'ab')) # False (zero edits)
print(is_one_edit_distance('ab', 'abc')) # True (append c)
print(is_one_edit_distance('ab', 'xyz')) # FalsePerbandingan Jarak Edit dan LCS
Jarak edit (dengan ketiga operasi) dan LCS merupakan cara pandang yang saling melengkapi terhadap kemiripan teks. Jarak edit menghitung perbedaan; LCS menghitung kemiripan. Jika hanya penyisipan dan penghapusan yang diizinkan (tanpa penggantian), jarak edit = m + n - 2×LCS. Jika penggantian diizinkan, DP-nya sedikit berbeda: nilai diagonal menyumbang dp[i-1][j-1] saat cocok (tanpa biaya) atau dp[i-1][j-1]+1 saat diganti. Kedua algoritme berjalan dalam waktu O(mn).
def lcs_len(s1, s2):
m, n = len(s1), len(s2)
dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(1,m+1):
for j in range(1,n+1):
if s1[i-1]==s2[j-1]: dp[i][j]=dp[i-1][j-1]+1
else: dp[i][j]=max(dp[i-1][j],dp[i][j-1])
return dp[m][n]
def edit_insert_delete_only(s1, s2):
return len(s1) + len(s2) - 2 * lcs_len(s1, s2)
print(edit_insert_delete_only('sea', 'eat')) # 2
print(edit_distance('sea', 'eat')) # 2 (same here: replace not needed)Pencocokan Teks Samar
Jarak edit mendukung pencocokan teks samar di dunia nyata. Pemeriksa ejaan menyarankan koreksi yang jaraknya 1 atau 2 operasi edit dari kata yang diketik. Tantangan pada skala besar adalah menghindari perbandingan O(mn × ukuran_kamus). Solusinya mencakup pohon BK (pohon metrik untuk jarak edit), pengindeksan n-gram, dan algoritme pencocokan teks hampiran seperti Bitap. Memahami DP yang mendasarinya membantu Anda menalar efisiensi alat tingkat lebih tinggi ini.
def spell_suggest(typed, dictionary, max_dist=2):
'''Return words in dictionary within max_dist edits of typed.'''
suggestions = []
for word in dictionary:
if abs(len(typed) - len(word)) <= max_dist:
if edit_distance(typed, word) <= max_dist:
suggestions.append(word)
return suggestions
def edit_distance(w1, w2):
dp = list(range(len(w2)+1))
for i,c1 in enumerate(w1,1):
prev = i
for j,c2 in enumerate(w2,1):
temp = dp[j]
dp[j] = prev if c1==c2 else 1+min(dp[j],prev,dp[j-1])
prev = temp
return dp[len(w2)]
dictionary = ['horse', 'worse', 'house', 'morse', 'nurse']
print(spell_suggest('harse', dictionary)) # horse, worse, house, morseJarak Edit Berbobot
Dalam beberapa aplikasi, operasi yang berbeda memiliki biaya yang berbeda pula. Sebagai contoh, menukar posisi karakter yang bersebelahan (kesalahan ketik umum) mungkin memerlukan biaya yang lebih rendah daripada penggantian penuh. Jarak Damerau-Levenshtein menambahkan penukaran posisi sebagai operasi keempat. DP-nya diperluas dengan turut memeriksa dp[i-2][j-2]+1 saat word1[i-1]==word2[j-2] dan word1[i-2]==word2[j-1]. Model ini lebih akurat untuk kesalahan ketik pada papan ketik.
def damerau_levenshtein(s, t):
m, n = len(s), len(t)
dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(m+1): dp[i][0]=i
for j in range(n+1): dp[0][j]=j
for i in range(1,m+1):
for j in range(1,n+1):
cost = 0 if s[i-1]==t[j-1] else 1
dp[i][j] = min(
dp[i-1][j]+1, # delete
dp[i][j-1]+1, # insert
dp[i-1][j-1]+cost # replace
)
# Transposition
if i>1 and j>1 and s[i-1]==t[j-2] and s[i-2]==t[j-1]:
dp[i][j] = min(dp[i][j], dp[i-2][j-2]+1)
return dp[m][n]
print(damerau_levenshtein('CA', 'ABC')) # 2
print(damerau_levenshtein('ab', 'ba')) # 1 (transposition)Penyelarasan Urutan DNA
Bioinformatika menggunakan varian jarak edit untuk penyelarasan urutan DNA. Algoritme Needleman-Wunsch adalah DP penyelarasan global yang berkaitan erat dengan LCS dan jarak edit, dengan kecocokan bernilai +1, ketidakcocokan bernilai -1, dan celah (penyisipan/penghapusan) dikenai penalti. Varian Smith-Waterman melakukan penyelarasan lokal (menemukan subrentetan dengan kecocokan terbaik). Keduanya merupakan algoritme DP O(mn) dengan struktur pengisian tabel yang sama.
def needleman_wunsch(seq1, seq2, match=1, mismatch=-1, gap=-1):
m, n = len(seq1), len(seq2)
dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(m+1): dp[i][0] = i * gap
for j in range(n+1): dp[0][j] = j * gap
for i in range(1,m+1):
for j in range(1,n+1):
score = match if seq1[i-1]==seq2[j-1] else mismatch
dp[i][j] = max(
dp[i-1][j-1] + score, # align
dp[i-1][j] + gap, # gap in seq2
dp[i][j-1] + gap # gap in seq1
)
return dp[m][n]
print(needleman_wunsch('GATTACA', 'GCATGCU')) # alignment scorePendekatan Wawancara untuk Jarak Edit
Saat ditanya tentang jarak edit dalam wawancara: (1) Pastikan operasi yang diizinkan (penyisipan/penghapusan/penggantian). (2) Definisikan keadaan DP dengan jelas. (3) Tuliskan ketiga kasus dan relasi rekurensinya secara eksplisit. (4) Nyatakan kasus dasar: dp[i][0]=i dan dp[0][j]=j. (5) Sebutkan optimasi ruang O(n). (6) Jika waktu memungkinkan, telusuri contoh kecil seperti 'cat'→'cut' (1 penggantian) untuk memvalidasi. Waktu O(mn) dan ruang O(mn) → O(n) merupakan batas kompleksitas standar.
# Clean interview solution
def min_distance(word1, word2):
m, n = len(word1), len(word2)
# O(n) space with rolling row
dp = list(range(n + 1))
for i in range(1, m + 1):
diag = dp[0] # dp[i-1][0]
dp[0] = i
for j in range(1, n + 1):
temp = dp[j]
if word1[i-1] == word2[j-1]:
dp[j] = diag
else:
dp[j] = 1 + min(dp[j], dp[j-1], diag)
diag = temp
return dp[n]
# Time: O(mn), Space: O(n)
print(min_distance('horse', 'ros')) # 3
print(min_distance('intention', 'execution')) # 5
print(min_distance('', 'abc')) # 3
print(min_distance('abc', '')) # 3Pemeriksaan Singkat
Uji pemahaman Anda tentang konsep Struktur Data & Algoritme — Persiapan Wawancara Pemrograman dari pelajaran ini.
Rangkuman Pelajaran
Dalam pelajaran ini Anda mempelajari: jarak edit dp[i][j] = min(dp[i][j-1]+1, dp[i-1][j]+1, dp[i-1][j-1]+cost) dengan biaya=0 saat cocok, dan 1 jika tidak, kasus dasar dp[i][0]=i dan dp[0][j]=j merepresentasikan transformasi ke atau dari teks kosong, serta optimasi ruang O(n) menggunakan larik 1D bergulir dengan variabel diagonal. Selanjutnya kita akan menerapkan trik larik bergulir yang sama untuk mengurangi tabel DP 2D dari ruang O(mn) menjadi O(min(m,n)).
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Jarak Edit (Levenshtein)” gratis?
Ya — teks lengkap “Jarak Edit (Levenshtein)” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus DSA Interview Prep, upgrade ke CoddyKit PRO. Kursus DSA Interview Prep mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Jarak Edit (Levenshtein)”?
Turunkan relasi rekurensi jarak edit untuk operasi penyisipan/penghapusan/penggantian, lalu isi tabel DP untuk pasangan string dengan panjang beragam. Kamu berlatih DSA Interview Prep dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai DSA Interview Prep?
Tidak diperlukan pengalaman sebelumnya. DSA Interview Prep di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “Jarak Edit (Levenshtein)” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran DSA Interview Prep ini?
Ya. Setiap pelajaran DSA Interview Prep menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Jalur Unik dan Jumlah Jalur Minimum pada Grid
- Longest Common Subsequence
- Jarak Edit (Levenshtein)
- Optimasi Ruang untuk DP 2D