In information theory and computer science, the Damerau–Levenshtein distance (named after Frederick J. Damerau and Vladimir I. Levenshtein) is a string metric for measuring the edit distance between two sequences. Informally, the Damerau–Levenshtein distance between two words is the minimum number of operations (consisting of insertions, deletions or substitutions of a single character, or transposition of two adjacent characters) required to change one word into the other.
The Damerau–Levenshtein distance differs from the classical Levenshtein distance by including transpositions among its allowable operations in addition to the three classical single-character edit operations (insertions, deletions and substitutions).
In his seminal paper, Damerau stated that in an investigation of spelling errors for an information-retrieval system, more than 80% were a result of a single error of one of the four types. Damerau's paper considered only misspellings that could be corrected with at most one edit operation. While the original motivation was to measure distance between human misspellings to improve applications such as spell checkers, Damerau–Levenshtein distance has also seen uses in biology to measure the variation between protein sequences.
Definition
To express the Damerau–Levenshtein distance between two strings and , a function is defined, whose value is a distance between an prefix (initial substring) of string and a prefix of .
The restricted distance function is defined recursively as:
where is the indicator function equal to 0 when and equal to 1 otherwise.
Each recursive call matches one of the cases covered by the Damerau–Levenshtein distance: corresponds to a deletion (from a to b), corresponds to an insertion (from a to b), corresponds to a match or mismatch, depending on whether the respective symbols are the same, corresponds to a transposition between two successive symbols.
The Damerau–Levenshtein distance between and is then given by the function value for full strings: , where denotes the length of string , and is the length of .
Algorithm
Presented here are two algorithms: the first, simpler one, computes what is known as the optimal string alignment distance or restricted edit distance, while the second one computes the Damerau–Levenshtein distance with adjacent transpositions. Adding transpositions adds significant complexity. The difference between the two algorithms consists in that the optimal string alignment algorithm computes the number of edit operations needed to make the strings equal under the condition that no substring is edited more than once, whereas the second one presents no such restriction.
Take for example the edit distance between CA and ABC. The Damerau–Levenshtein distance LD(CA, ABC) = 2 because CA → AC → ABC, but the optimal string alignment distance OSA(CA, ABC) = 3 because if the operation CA → AC is used, it is not possible to use AC → ABC because that would require the substring to be edited more than once, which is not allowed in OSA, and therefore the shortest sequence of operations is CA → A → AB → ABC. Note that for the optimal string alignment distance, the triangle inequality does not hold: OSA(CA, AC) + OSA(AC, ABC) < OSA(CA, ABC), and so it is not a true metric.
Optimal string alignment distance
Optimal string alignment distance can be computed using a straightforward extension of the Wagner–Fischer dynamic programming algorithm that computes Levenshtein distance. In pseudocode:
algorithm OSA-distance is
input: strings a[1..length(a)], b[1..length(b)]
output: distance, integer
let d[0..length(a), 0..length(b)] be a 2-d array of integers, dimensions length(a)+1, length(b)+1 // note that d is zero-indexed, while a and b are one-indexed.
for i := 0 to length(a) inclusive do
d[i, 0] := i
for j := 0 to length(b) inclusive do
d[0, j] := j
for i := 1 to length(a) inclusive do
for j := 1 to length(b) inclusive do
if a[i] = b[j] then
cost := 0
else
cost := 1
d[i, j] := minimum(d[i-1, j] + 1, // deletion
d[i, j-1] + 1, // insertion
d[i-1, j-1] + cost) // substitution
if i > 1 and j > 1 and a[i] = b[j-1] and a[i-1] = b[j] then
d[i, j] := minimum(d[i, j], d[i-2, j-2] + 1) // transposition return d[length(a), length(b)]
The difference from the algorithm for Levenshtein distance is the addition of one recurrence:
if i > 1 and j > 1 and a[i] = b[j-1] and a[i-1] = b[j] then
d[i, j] := minimum(d[i, j], d[i-2, j-2] + 1) // transposition