Levenshtein distance
string similarity
edit distance
algorithm
computational linguistics

String similarity - Levenshtein distance

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Levenshtein distance measures how many single-character edits are required to transform one string into another. It is one of the most useful baseline metrics for spelling correction, fuzzy matching, deduplication, and search, because it turns a vague idea of "similar text" into a concrete edit count.

What the Distance Counts

The standard Levenshtein metric allows three operations:

  • insert one character
  • delete one character
  • substitute one character

So the distance between kitten and sitting is 3:

  • substitute k with s
  • substitute e with i
  • insert g

A smaller distance means the strings are closer. A distance of 0 means the strings are identical.

Dynamic Programming Solution

The classic algorithm builds a matrix where each cell stores the minimum edit count for prefixes of the two strings. That avoids the exponential blowup of naive recursion.

A space-efficient Python implementation keeps only one row at a time:

python
1
2def levenshtein(a, b):
3    if len(a) < len(b):
4        a, b = b, a
5
6    previous = list(range(len(b) + 1))
7
8    for i, ca in enumerate(a, start=1):
9        current = [i]
10        for j, cb in enumerate(b, start=1):
11            insert_cost = current[j - 1] + 1
12            delete_cost = previous[j] + 1
13            replace_cost = previous[j - 1] + (ca != cb)
14            current.append(min(insert_cost, delete_cost, replace_cost))
15        previous = current
16
17    return previous[-1]
18
19
20print(levenshtein("kitten", "sitting"))
21print(levenshtein("book", "back"))

This runs in O(mn) time and O(min(m, n)) extra space.

Distance Versus Similarity Score

Levenshtein distance is a difference measure, not a similarity percentage. If you want a normalized similarity score, convert it explicitly.

python
1
2def normalized_similarity(a, b):
3    if not a and not b:
4        return 1.0
5    dist = levenshtein(a, b)
6    return 1.0 - dist / max(len(a), len(b))
7
8
9print(normalized_similarity("kitten", "sitting"))

This is useful when comparing strings of different lengths, because a raw distance of 2 means something very different for strings of length 4 versus length 40.

Where It Works Well

Levenshtein distance is good when edits are local and characters matter directly. Typical use cases include:

  • spell checking and autocomplete fallback
  • matching user-entered names with minor typos
  • ranking near-duplicate identifiers
  • approximate matching in small dictionaries

It is especially useful as a baseline because it is easy to explain and easy to test.

Where It Falls Short

Not all similarity problems are edit-distance problems.

If adjacent transpositions should count as one error, standard Levenshtein may be too strict. In that case, Damerau-Levenshtein is often a better fit.

If token order, phonetics, or meaning matter more than character edits, other techniques may outperform it entirely. For example, comparing full names, sentences, or product titles often benefits from token-based or embedding-based methods.

Unicode and Preprocessing Matter

Text that looks identical to users may have different Unicode representations. Before measuring distance, normalize the strings and decide whether case, accents, whitespace, or punctuation should matter.

python
1import unicodedata
2
3
4def canonicalize(text):
5    return unicodedata.normalize("NFC", text).casefold().strip()
6
7
8print(levenshtein(canonicalize("Cafe"), canonicalize("café")))

Without preprocessing, your metric may be correct technically and still wrong for the business problem.

Common Pitfalls

A common mistake is using raw distance as if it were already a similarity percentage. Distance 2 is not inherently "good" or "bad" without context.

Another mistake is applying Levenshtein to long strings where semantic similarity matters more than character edits. It becomes expensive and often less meaningful.

Developers also forget normalization, which leads to misleading differences caused by case, whitespace, or Unicode composition rather than real content changes.

Summary

  • Levenshtein distance counts insertions, deletions, and substitutions.
  • Dynamic programming computes it efficiently in O(mn) time.
  • Normalize the result if you need a similarity score instead of an edit count.
  • It works well for typos and short fuzzy matches, not for every text problem.
  • Preprocessing and Unicode normalization are often just as important as the distance formula itself.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.