Edit Metrics and Dynamic Programming
A string distance assigns a cost to transforming one sequence into another. The chosen operations determine both the meaning of the distance and the recurrence needed to compute it. Hamming distance compares aligned positions and therefore requires equal-length strings. Levenshtein distance permits insertion, deletion, and substitution, while weighted variants assign application-specific costs to those operations. Damerau–Levenshtein distance additionally permits transposing adjacent symbols.
For strings $A$ and $B$, define $D[i][j]$ as the minimum cost of transforming $A[0 \dots i)$ into $B[0 \dots j)$. Under unit-cost Levenshtein distance, $D[i][0]=i$, $D[0][j]=j$, and
$$ D[i][j]=\min\left(D[i-1][j]+1,\ D[i][j-1]+1,\ D[i-1][j-1]+[A[i-1]\ne B[j-1]]\right). $$
Weighted distance replaces unit costs with operation-dependent functions. Metric guarantees require non-negative symmetric costs, identity of indiscernibles, and triangle-compatible costs. Restricted optimal-string-alignment distance adds $D[i-2][j-2]$ for a reversed adjacent pair but cannot edit the same substring twice; full Damerau–Levenshtein uses last-occurrence information to support interacting transpositions.
| Distance | Allowed operations | Input restriction | DP state or computation | Metric status | Typical use |
|---|---|---|---|---|---|
| Hamming | Position-wise substitutions | Equal lengths | Count unequal aligned positions | Metric on equal-length strings | Codes and fixed-length identifiers |
| Levenshtein | Insert, delete, substitute | None | $D[i][j]$ over two prefixes | Metric with unit costs | Typos and noisy text |
| Weighted Levenshtein | Weighted insertions, deletions, substitutions | None | Prefix DP with operation costs | Metric only under suitable cost rules | Keyboard-aware correction |
| Optimal string alignment | Basic edits plus one adjacent transposition per affected substring | None | Prefix DP plus $D[i-2][j-2]$ | Generally not a metric | Isolated swapped-letter typos |
| Full Damerau–Levenshtein | Basic edits plus adjacent transpositions | None | Prefix DP with previous-occurrence positions | Metric under unit costs | Interacting adjacent swaps |
Alignment Reconstruction and Acceleration
The full $O(nm)$ table supports traceback. From $(n,m)$, a diagonal move aligns two symbols, an upward move deletes a source symbol, and a leftward move inserts a target symbol. Reversing these choices produces an optimal alignment. When only the distance is needed, rolling rows reduce auxiliary space to $O(\min(n,m))$.
If the distance is at most $k$, a valid path cannot leave the band $|i-j|\le k$. Banded DP evaluates $O(k)$ cells per row, while thresholded Ukkonen search stops when no state can satisfy the bound. Myers' bit-vector algorithm packs many DP states into machine words and is especially effective for short patterns.
The LCS Family and Diff
Let $L[i][j]$ be the LCS length of $A[0 \dots i)$ and $B[0 \dots j)$. Matching final symbols extend $L[i-1][j-1]$; otherwise take $\max(L[i-1][j],L[i][j-1])$. If only insertions and deletions cost one, an LCS of length $\ell$ yields distance $|A|+|B|-2\ell$ and shortest-common-supersequence length $|A|+|B|-\ell$.
Standard DP costs $O(nm)$ time and space. Hirschberg reconstructs an LCS in linear auxiliary space by combining forward and reverse rows. Hunt–Szymanski processes matching-position lists and excels when the number of matching pairs is small. Bitset algorithms update many states per machine operation. Diff tools turn an LCS backbone into insertions and deletions; tie-breaking among optimal witnesses affects readability.
flowchart TD
INPUT["Strings A and B"]
LCS["LCS length = l"]
KEEP["Keep l shared symbols"]
EDITS["Insert/delete distance = |A| + |B| - 2l"]
SCS["Shortest common supersequence = |A| + |B| - l"]
INPUT --> LCS
LCS --> KEEP
KEEP -->|"delete |A| - l; insert |B| - l"| EDITS
KEEP -->|"merge unmatched symbols"| SCS
Global and Local Sequence Alignment
Needleman–Wunsch computes a global alignment, forcing both sequences to participate from beginning to end. Smith–Waterman computes a local alignment by allowing states to restart at zero; traceback begins at the maximum cell and stops at zero. Semi-global alignment makes selected terminal gaps free, which suits fitting a short read into a longer reference.
With affine gaps, a length-$k$ gap costs $g_o+(k-1)g_e$. Gotoh's algorithm retains $O(nm)$ time using three states: $M$ ends in a symbol pair, $X$ ends in a gap in the second sequence, and $Y$ ends in a gap in the first.
Alignment Trace
Globally align $A=\text{"AC"}$ with $B=\text{"A"}$ using match $+2$, mismatch $-1$, gap open $-2$, and gap extension $-1$. The first symbol in a gap costs $-2$.
- Initialize $M[0][0]=0$ and impossible states to $-\infty$.
- At $(1,1)$, align
AwithA: $M[1][1]=M[0][0]+2=2$. - Consume
Cby opening a gap in $B$: $X[2][1]=\max(M[1][1]-2,X[1][1]-1)=0$. - Traceback moves from $X[2][1]$ to $M[1][1]$ and then to the origin. The resulting aligned rows are
ACandA-.
The final score is $0$. A further symbol in the same gap would cost only the extension penalty $-1$.
Approximate Search Filters and Indexes
Approximate Bitap extends Shift-Or with one bit-vector level per error and works well for short patterns. Myers' bit-vector method similarly accelerates Levenshtein matching. A $q$-gram filter rejects candidates with insufficient fragment overlap; pigeonhole filtering splits a pattern into $k+1$ pieces so that an alignment with at most $k$ errors must preserve an appropriate seed. Seed-and-extend searches seeds first and verifies only nearby candidates.
BK-trees organize strings under a metric: after measuring distance $d$ to a node, a radius-$k$ query visits only child edges in $[d-k,d+k]$. Levenshtein automata recognize all strings within distance $k$ of a fixed pattern and can be intersected with a trie or finite-state dictionary. Filters must be followed by exact verification unless their construction itself proves the final guarantee.
A $k$-mismatch guarantee normally permits substitutions only at aligned positions, while a $k$-edit guarantee also permits insertions and deletions. A Hamming or mismatch filter cannot establish Levenshtein correctness unless it explicitly accounts for alignment shifts.
Next in the Series
In Automata, Regular Expressions & Parsing, we'll explore Finite automata, regex engines, context-free grammars, parsing families, and lexical processing.