Skip to content
BytePatterns

Edit Distance

Dynamic Programming: lesson 8 of 10

Insert, delete, or replace — count the cheapest route.

Lesson 8 of 10 · 6 min

Edit Distance

Step 1 of 20

Turn flaw into lawn. One row per prefix of the first word, one column per prefix of the second.

The Idea

Turn one string into another with inserts, deletes, and replacements, counting the cheapest sequence. Every grid cell asks what the three slightly shorter problems cost. Matching characters are free and copy the diagonal; a mismatch pays one on top of whichever of the three neighbours is cheapest. Only the previous row is ever needed.

Real-World Example

The "did you mean" line under a mistyped search. The engine scores your typo against dictionary words by how many single-character fixes separate them, so a word one edit away is offered before one that is three edits away.

The Code

def edit(a, b):
    row = list(range(len(b) + 1))                 # cost of building b's prefixes from ""
    for i in range(1, len(a) + 1):
        new = [i] + [0] * len(b)
        for j in range(1, len(b) + 1):
            cost = 0 if a[i - 1] == b[j - 1] else 1
            new[j] = min(row[j] + 1,              # delete
                         new[j - 1] + 1,          # insert
                         row[j - 1] + cost)       # match or replace
        row = new
    return row[len(b)]

print(edit("kitten", "sitting"))   # 3
print(edit("flaw", "lawn"))        # 2

Your turn

Put the steps in the right order.

  1. Fill each remaining cell with the cheapest of delete, insert, and replace
  2. Read the bottom-right cell as the distance
  3. Fill row 0 and column 0 with 0, 1, 2, ... — the cost against an empty string
  4. Lay out a grid with one row per prefix of a and one column per prefix of b

Mini quiz

1 / 3

The three operations scored by edit distance are: