Edit Distance and the Levenshtein Algorithm

Matt George

Fractional CTO · Founder of Injuria.ai

•19 min read•

Edit distance is a fundamental string metric in computer science used to quantify the dissimilarity between two sequences of characters.[34] While the term is sometimes used as a broad category for various string matching metrics, it most commonly refers specifically to the Levenshtein distance. This metric measures the minimum number of single-character editing operations required to transform one string into another. The allowable operations in the standard Levenshtein model are insertions, deletions, and substitutions. By assigning a mathematical cost to these operations, the metric provides a deterministic and rigorous method for evaluating how far apart two strings are in a theoretical metric space.

The ability to measure sequence similarity is a foundational requirement across multiple disciplines, including natural language processing, bioinformatics, and database management. Exact string matching algorithms, which operate in linear time, are highly efficient but fail completely if a single character is altered. Exact matching is insufficient for handling the noisy data frequently encountered in real systems. Human typists make spelling errors, optical character recognition software misinterprets scanned letters, and biological reproduction introduces genetic mutations. The Levenshtein distance addresses these inconsistencies by formalizing the concept of approximate string matching, allowing systems to identify targets that are close to a query even if they do not match exactly.

To compute this distance efficiently, computer scientists rely on the Levenshtein algorithm, a dynamic programming technique that breaks the transformation process down into a matrix of overlapping subproblems.[35] This algorithmic approach guarantees the discovery of the optimal sequence of edits. Today, the algorithm and its many optimized variants are embedded in the core of modern software infrastructure. It powers the spell checking engines in word processors, the fuzzy search capabilities of distributed databases, and the sequence alignment tools used to map the human genome.

Mathematical Definition

The Levenshtein distance between two strings can be formalized as a mathematical function operating over a finite alphabet. Let $a$ and $b$ be two strings of lengths $m$ and $n$, respectively. The characters of the strings are indexed starting from 1, such that $a_i$ represents the $i$-th character of string $a$, and $b_j$ represents the $j$-th character of string $b$. The distance is defined by a piecewise recursive function, typically denoted as $\operatorname{lev}(a, b)$.

To evaluate the distance, the function considers the prefixes of the two strings. Let $\operatorname{lev}_{a,b}(i, j)$ represent the distance between the first $i$ characters of $a$ and the first $j$ characters of $b$. The base cases for the recursion occur when one of the strings is empty. If $i = 0$, the only way to transform the empty string into a string of length $j$ is to perform $j$ insertions. If $j = 0$, the only way to transform a string of length $i$ into an empty string is to perform $i$ deletions. Therefore, if $\min(i, j) = 0$, the function evaluates to $\max(i, j)$.

When both $i$ and $j$ are greater than zero, the function evaluates the cost of three possible operations and selects the minimum value among them. The three operations are:

  1. Deletion: $\operatorname{lev}_{a,b}(i-1, j) + 1$. This represents deleting the character $a_i$ and matching the remaining $i-1$ characters to the $j$ characters of $b$.
  2. Insertion: $\operatorname{lev}_{a,b}(i, j-1) + 1$. This represents inserting the character $b_j$ and matching the $i$ characters of $a$ to the remaining $j-1$ characters of $b$.
  3. Substitution: $\operatorname{lev}{a,b}(i-1, j-1) + 1{(a_i \neq b_j)}$. This represents substituting $a_i$ for $b_j$. The term $1_{(a_i \neq b_j)}$ is an indicator function that equals 0 if the characters are identical (requiring no edit) and 1 if they are different.

This standard definition assumes a uniform cost model where every operation costs exactly 1. However, the mathematical framework easily adapts to a weighted edit distance model. In a weighted model, the costs of insertion, deletion, and substitution are defined as distinct variables. For example, optical character recognition systems might assign a lower substitution cost for visually similar characters (like 'O' and '0') and a higher cost for visually distinct characters. If the cost of substitution is set to be greater than or equal to the combined cost of an insertion and a deletion, the algorithm will never choose to substitute, effectively reducing the model to the Longest Common Subsequence metric.

The standard Levenshtein distance satisfies the four strict mathematical conditions required to form a metric space. First, the distance is always non-negative; it is impossible to have a negative number of edits. Second, it satisfies the identity of indiscernibles, meaning the distance between two strings is zero if and only if the strings are exactly identical. Third, the metric is symmetric, meaning the distance from string $a$ to string $b$ is exactly the same as the distance from string $b$ to string $a$. An insertion in one direction is simply a deletion in the other. Finally, it satisfies the triangle inequality. For any three strings $a$, $b$, and $c$, the distance from $a$ to $c$ is always less than or equal to the distance from $a$ to $b$ plus the distance from $b$ to $c$.

These metric properties are highly valuable in computer science because they allow the distance to be indexed using specialized data structures like Burkhard-Keller trees[1], introduced by Walter A. Burkhard and Robert M. Keller in 1973. A BK-tree relies on the triangle inequality to prune search spaces efficiently. When searching a dictionary for a string within a specific maximum distance, the tree structure allows the algorithm to discard entire branches that mathematically cannot contain a valid match, reducing the search time from linear to logarithmic in many practical scenarios.

The Levenshtein Algorithm

A naive implementation of the recursive mathematical definition is highly inefficient. Because the recursive branches overlap, a direct recursive function recalculates the same prefix distances repeatedly, leading to an exponential time complexity. To solve this, the standard Levenshtein algorithm utilizes dynamic programming, a method formalized by Richard Bellman in 1957[2] that stores the results of subproblems in memory to avoid redundant computation.

The dynamic programming approach constructs a two-dimensional matrix $D$ with $m+1$ rows and $n+1$ columns. The rows represent the prefixes of string $a$ (from length 0 to $m$), and the columns represent the prefixes of string $b$ (from length 0 to $n$). The value stored in any cell $D[i][j]$ represents the exact Levenshtein distance between the first $i$ characters of $a$ and the first $j$ characters of $b$.

The algorithm begins by initializing the first row and the first column of the matrix. The cell $D[0][0]$ is set to 0, representing the cost of comparing two empty strings. The rest of the first row is initialized such that $D[0][j] = j$, representing the cost of inserting $j$ characters. The first column is initialized such that $D[i][0] = i$, representing the cost of deleting $i$ characters.

After initialization, the algorithm iterates through the remaining cells of the matrix using nested loops. For each cell $D[i][j]$, it calculates the cost of deletion (the value in the cell directly above plus one), the cost of insertion (the value in the cell directly to the left plus one), and the cost of substitution (the value in the diagonal cell to the upper-left, plus one if the current characters differ, or plus zero if they match). The cell $D[i][j]$ is then assigned the minimum of these three values. Once the loops terminate, the final distance is located in the bottom-right cell of the matrix, $D[m][n]$.

function LevenshteinDistance(char a[1..m], char b[1..n]):
    declare int D[0..m, 0..n]
    
    for i from 0 to m:
        D[i, 0] = i
    for j from 0 to n:
        D[0, j] = j
        
    for i from 1 to m:
        for j from 1 to n:
            if a[i] == b[j]:
                substitutionCost = 0
            else:
                substitutionCost = 1
                
            D[i, j] = minimum(
                D[i-1, j] + 1,                   // deletion
                D[i, j-1] + 1,                   // insertion
                D[i-1, j-1] + substitutionCost   // substitution
            )
            
    return D[m, n]

To illustrate the mechanics of the matrix, consider transforming the string "cat" into "cars". The matrix requires 4 rows (indexed 0 to 3) and 5 columns (indexed 0 to 4). The algorithm initializes the first row with the values 0, 1, 2, 3, 4 and the first column with the values 0, 1, 2, 3.

When evaluating the first characters ('c' and 'c') at cell $D[1][1]$, the algorithm looks at the diagonal value $D[0][0]$, which is 0. Since the characters match, the substitution cost is 0, resulting in a value of 0 for $D[1][1]$. The algorithm proceeds row by row. When comparing the entire strings at the bottom right cell $D[3][4]$ (comparing 't' to 's'), the algorithm evaluates the cost of deleting 't' (looking at $D[2][4] + 1$), inserting 's' (looking at $D[3][3] + 1$), or substituting 't' for 's' (looking at $D[2][3] + 1$).

Finding the numerical distance is only one part of the problem. Many applications require the exact sequence of operations, known as the alignment. To find this alignment, algorithms perform a traceback phase. Starting from the bottom-right cell $D[m][n]$, the algorithm examines the adjacent cells that could have produced the current cell's value. It moves to the cell that provided the minimum cost, recording the corresponding operation. This process continues until it reaches the top-left cell $D[0][0]$. Because multiple paths might yield the same minimum cost, there can be multiple optimal alignments for a single pair of strings.

The time complexity of this algorithm is $O(mn)$ in Big-O notation. The matrix contains $(m+1) \times (n+1)$ cells, and computing the value for each cell requires a constant $O(1)$ number of basic arithmetic operations.

The native space complexity is also $O(mn)$ because the entire matrix is allocated in memory. However, the space complexity can be heavily optimized. Because the recurrence relation for row $i$ only depends on the values in row $i$ and row $i-1$, the algorithm does not need to store the entire matrix. By keeping only two rows in memory at any given time, the space complexity drops to $O(n)$. By ensuring the shorter string is mapped to the columns, this can be strictly bounded to $O(\min(m, n))$. Further optimization allows the algorithm to use a single row array alongside a few scalar variables to track the upper-left diagonal value, completely eliminating the need for a second array.

Discovery and History

The metric is named after Vladimir Levenshtein, a Soviet mathematician who formalized the concept in 1965 while working at the Keldysh Institute of Applied Mathematics (he graduated from Moscow State University in 1958). His foundational paper, published in Russian in Doklady Akademii Nauk SSSR and translated to English in 1966 as "Binary codes capable of correcting deletions, insertions, and reversals"[3] in Soviet Physics Doklady, did not propose a computer algorithm for string matching.

Instead, Levenshtein was working in the field of information theory and coding theory. Following Claude Shannon's 1948 formalization[4] of communication over noisy channels in the Bell System Technical Journal, researchers sought ways to encode data so that errors could be detected and corrected. This research was heavily funded during the Cold War to ensure reliable military and satellite communications. While classical error-correcting codes, such as those developed by Richard Hamming in 1950[5], were designed to handle substitution errors (where a 0 flips to a 1 or vice versa), they failed catastrophically if a bit was inserted or deleted.

An insertion or deletion causes a loss of synchronization, shifting the entire subsequent sequence out of alignment. Levenshtein defined the metric of insertions, deletions, and substitutions to prove mathematical bounds on the redundancy required to construct codes capable of surviving these synchronization errors. He proved that a code capable of correcting a specific number of deletions can also correct the same number of insertions. The distance metric was a theoretical construct used to prove these bounds, rather than a software implementation intended for text processing.

Independent Co-Discoveries and Prior Art

Because the problem of sequence alignment is universal, the dynamic programming algorithm used to compute the distance was discovered independently by multiple researchers across different scientific disciplines in the late 1960s and early 1970s.

In 1968, the Soviet scientist Taras Vintsyuk published "Speech discrimination by dynamic programming"[6] in the journal Cybernetics. Vintsyuk applied dynamic programming to the time alignment of speech signals. Because human speakers dictate words at varying speeds, audio signals must be warped in time to match a template. Vintsyuk's work, later expanded by Hiroaki Sakoe and Seibi Chiba in 1978[7], laid the foundation for Dynamic Time Warping, a continuous analog to the discrete Levenshtein algorithm.

In 1970, Saul B. Needleman and Christian D. Wunsch published [8] in the Journal of Molecular Biology. Working in bioinformatics, they developed a global alignment algorithm to compare biological macromolecules. The Needleman-Wunsch algorithm is mathematically equivalent to the Levenshtein algorithm, though it is typically framed in terms of maximizing a similarity score using biological substitution matrices rather than minimizing a uniform distance penalty.

In 1972, David Sankoff[9] published work on matching sequences under deletion and insertion constraints, further formalizing the mathematics of sequence comparison in computational biology. In 1974, Peter H. Sellers[10] published algorithms for computing evolutionary distances, proving that the distance metric satisfied the triangle inequality.

The formalization of the algorithm specifically for computer science and string correction is credited to Robert A. Wagner and Michael J. Fischer. In 1974, they published "The String-to-String Correction Problem"[11] in the Journal of the ACM. Wagner and Fischer explicitly defined the $O(mn)$ dynamic programming algorithm, proved its optimality, and analyzed its time and space complexity. Their paper cemented the algorithm as a standard tool in computer science, specifically targeting applications like spelling correction and compiler error recovery.

Algorithmic Refinements

While the $O(mn)$ time complexity of the standard algorithm is acceptable for short strings, it becomes a severe bottleneck when comparing long sequences, such as entire text files or DNA strands. Over the decades, computer scientists developed several refinements to optimize the computation.

In 1975, Daniel S. Hirschberg published "A linear space algorithm for computing maximal common subsequences"[12] in the Communications of the ACM. Computing the full matrix for two strings of 100,000 characters requires 10 billion integers of memory, which was impossible on early hardware. Hirschberg applied a divide-and-conquer strategy to the dynamic programming matrix. By computing the matrix from both the forward and reverse directions, his algorithm finds the midpoint of the optimal alignment. It then recursively splits the problem into smaller halves. This technique reduces the space complexity to $O(m+n)$ while maintaining the $O(mn)$ time complexity, allowing for the alignment of massive sequences.

In 1980, William J. Masek and Michael S. Paterson published "A faster algorithm computing string edit distances"[13] in the Journal of Computer and System Sciences. They applied the Method of Four Russians to the dynamic programming matrix. By dividing the matrix into small blocks and precomputing the optimal paths for all possible block combinations in a lookup table, their algorithm achieved a time complexity of $O(mn / \log(\max(m, n)))$. While theoretically faster for infinite strings, the overhead of building the lookup table makes this approach slower in practice for typical data sizes.

In 1985, Esko Ukkonen published "Algorithms for approximate string matching"[14] in Information and Control. Ukkonen observed that if the maximum allowed distance is bounded by a threshold $s$, the algorithm does not need to compute the entire matrix. Instead, it only needs to compute a diagonal band of width $2s+1$. If the values outside this band exceed the threshold, they can be safely ignored. This reduces the time complexity to $O(s \cdot \min(m, n))$, which is highly efficient when searching for near-exact matches.

In 1999, Gene Myers published "A fast bit-vector algorithm for approximate string matching based on dynamic programming"[15] in the Journal of the ACM. Myers recognized that the differences between adjacent cells in the dynamic programming matrix are always bounded by -1, 0, or +1. He designed an algorithm that encodes these differences as bits and processes them using bitwise logical operations (AND, OR, XOR). By computing multiple cells simultaneously within a single CPU register, Myers reduced the time complexity to $O(mn/w)$, where $w$ is the machine word size (typically 64). This bit-parallel approach remains one of the fastest known methods for exact edit distance computation.

Variants of Edit Distance

The standard Levenshtein distance is part of a broader family of string metrics, each tailored to specific types of sequence variations.

The Damerau-Levenshtein distance extends the standard metric by adding a fourth operation: the transposition of two adjacent characters. This variant was introduced by Fred J. Damerau in his 1964 paper "A technique for computer detection and correction of spelling errors"[16].[36] Damerau observed that transpositions account for a massive majority of human typing errors. In the standard Levenshtein model, fixing a transposition (such as typing "teh" instead of "the") requires two operations (a deletion and an insertion, or two substitutions). The Damerau-Levenshtein model counts it as a single operation, aligning the mathematics more closely with physical keyboard mistakes.

The Hamming distance[5], formalized in 1950, is a highly restrictive variant that only allows substitutions. It cannot handle insertions or deletions, meaning it can only compare strings of exactly the same length. It is primarily used in telecommunications for error detection in fixed-length binary packets.

The Longest Common Subsequence (LCS) metric is the inverse of the Hamming distance. It allows insertions and deletions but strictly forbids substitutions (or assigns them a cost of 2, equivalent to a deletion followed by an insertion). LCS is the mathematical foundation for file comparison utilities.

The Jaro and Jaro-Winkler distances, developed by Matthew A. Jaro in 1989[17] and refined by William E. Winkler in 1990[18], are not true mathematical metrics because they do not obey the triangle inequality. Instead, they are heuristic similarity measures designed for record linkage and deduplication of census data. They calculate similarity based on the number of matching characters within a sliding window and the number of transpositions. Winkler added a prefix scaling factor that gives more favorable ratings to strings that match from the beginning, which is highly effective for matching human names.

The Smith-Waterman algorithm[19], published in 1981, adapts the Needleman-Wunsch and Levenshtein concepts for local sequence alignment. Instead of forcing the entire strings to align, it resets negative matrix scores to zero. This allows the algorithm to ignore completely mismatched prefixes and suffixes, finding a highly similar region hidden in the middle of two larger sequences.

Real-World Applications

The Levenshtein algorithm and its variants are ubiquitous in modern computing, detailed extensively in comprehensive surveys such as Gonzalo Navarro's 2001 paper "A guided tour to approximate string matching"[20] and Dan Gusfield's 1997 textbook "Algorithms on Strings, Trees and Sequences"[21].

In word processing, open-source spell checking engines like GNU Aspell[22] and Hunspell[23] use edit distance to generate correction suggestions. To avoid comparing a misspelled word against all 100,000 words in a dictionary, these engines traverse a dictionary trie, calculating the distance dynamically and pruning branches that exceed a small threshold. This approach is often combined with statistical probability models, as demonstrated in Peter Norvig's 2007 essay on spelling correction[24], which uses edit distance to generate candidate words and Bayesian probability to select the most likely intended word based on corpus frequency.

In bioinformatics, the algorithm is the foundation for comparing genetic material. While pure dynamic programming is too slow for massive genome databases, heuristic tools like FASTA[25] and BLAST (Basic Local Alignment Search Tool)[26] use fast word-matching to find exact seed regions of length $k$. Once a seed is found, BLAST uses dynamic programming algorithms derived from Levenshtein and Smith-Waterman to extend the alignment outward and calculate the exact edit distance of the local match.

In database management, relational databases often provide native support for approximate matching. PostgreSQL includes the fuzzystrmatch module[27], which exposes a levenshtein function for querying text fields. Search engines like Elasticsearch and Apache Lucene implement fuzzy queries[28] to handle typos in user searches. To achieve high performance across millions of documents, Lucene constructs a Levenshtein automaton[29]. As detailed by Klaus Schulz and Stoyan Mihov in 2002[30], this technique converts the query string and the maximum edit distance into a deterministic finite automaton (DFA). The DFA is then intersected with the database's term dictionary to find all matching terms in linear time relative to the length of the dictionary terms, without scanning the entire database.

In version control systems, the diff utility[31] relies on the Longest Common Subsequence variant of edit distance to identify added and removed lines of code. These systems typically implement the Hunt-Szymanski algorithm (1977)[32] or the Myers diff algorithm to compute the minimal set of line edits required to transform one version of a file into the next, emitting the non-matching lines as insertions and deletions.

Significance and Tradeoffs

The primary significance of the Levenshtein algorithm is its mathematical certainty. Unlike heuristic approaches that might guess the similarity between two strings, dynamic programming guarantees the discovery of the absolute minimum number of operations required for the transformation. This optimality makes it the standard against which all other approximate string matching algorithms are measured.

The algorithm does have strict limitations. The $O(mn)$ time complexity is a severe tradeoff. Comparing two strings of one million characters each requires one trillion matrix operations. Without the band optimizations proposed by Ukkonen or the bit-vector parallelism proposed by Myers, the algorithm is computationally prohibitive for large-scale data analysis.

Theoretical computer science suggests that this quadratic time barrier is permanent. In 2015, Arturs Backurs and Piotr Indyk published "Edit Distance Cannot Be Computed in Strongly Subquadratic Time (unless SETH is false)"[33] at the ACM Symposium on Theory of Computing. They proved that if a general algorithm exists that can compute the edit distance in $O(n^{2-\epsilon})$ time, it could be used to solve the boolean satisfiability problem faster than exhaustive search. This would violate the Strong Exponential Time Hypothesis, a major unsolved problem in computational complexity theory. This proof strongly suggests that the $O(mn)$ time complexity of the standard dynamic programming approach is the absolute mathematical floor for exact edit distance computation, forcing engineers to rely on heuristics for massive datasets.

Another limitation is its lack of semantic awareness. The metric treats strings purely as sequences of arbitrary symbols. The words "cat" and "bat" have a Levenshtein distance of 1, indicating high similarity syntactically, even though they represent entirely different concepts. Conversely, the words "feline" and "cat" have a distance of 6, indicating no similarity, despite being synonyms. Because of this semantic gap, modern search engines and natural language processing systems rarely use edit distance in isolation. Instead, it is utilized as a low-level morphological filter, applied only after higher-level algorithms, such as term frequency-inverse document frequency (TF-IDF) or neural word embeddings, have established semantic relevance.

Sources (36)
  1. Burkhard-Keller trees
  2. press.princeton.edu: Richard Bellman in 1957
  3. "Binary codes capable of correcting deletions, insertions, and reversals"
  4. Claude Shannon's 1948 formalization
  5. Richard Hamming in 1950
  6. "Speech discrimination by dynamic programming"
  7. Hiroaki Sakoe and Seibi Chiba in 1978
  8. doi.org
  9. David Sankoff
  10. Peter H. Sellers
  11. "The String-to-String Correction Problem"
  12. "A linear space algorithm for computing maximal common subsequences"
  13. "A faster algorithm computing string edit distances"
  14. "Algorithms for approximate string matching"
  15. doi.org
  16. "A technique for computer detection and correction of spelling errors"
  17. Matthew A. Jaro in 1989
  18. William E. Winkler in 1990
  19. Smith-Waterman algorithm
  20. "A guided tour to approximate string matching"
  21. "Algorithms on Strings, Trees and Sequences"
  22. GNU Aspell
  23. Hunspell
  24. Peter Norvig's 2007 essay on spelling correction
  25. FASTA
  26. BLAST (Basic Local Alignment Search Tool)
  27. `fuzzystrmatch` module
  28. fuzzy queries
  29. Lucene constructs a Levenshtein automaton
  30. Klaus Schulz and Stoyan Mihov in 2002
  31. GNU Project
  32. Hunt-Szymanski algorithm (1977)
  33. ACM Digital Library
  34. Mohd Azlishah Othman, Mohamad Zoinol Abidin Abd Aziz, Mohd Shakir Md Saat, Proceedings of the 3rd International Symposium of Information and Internet Technology (SYMINTECH 2018) (Springer, 2019)
  35. Hujun Yin, David Camacho, Peter Tino, Intelligent Data Engineering and Automated Learning - IDEAL 2021 (Springer Nature, 2021)
  36. Ahmed El Oualkadi, Fethi Choubani, Ali El Moussati, Proceedings of the Mediterranean Conference on Information & Communication Technologies 2015 (Springer, 2016)

Recommended reading