0Pricing
DSA Interview Prep · Pelajaran

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')) # 5

Memahami 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')) # 5

Merekonstruksi 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'))   # False

Perbandingan 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, morse

Jarak 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 score

Pendekatan 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', ''))               # 3

Pemeriksaan 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

  1. Jalur Unik dan Jumlah Jalur Minimum pada Grid
  2. Longest Common Subsequence
  3. Jarak Edit (Levenshtein)
  4. Optimasi Ruang untuk DP 2D
← Kembali ke DSA Interview Prep