diff --git a/String/LevenshteinDistance.js b/String/LevenshteinDistance.js new file mode 100644 index 000000000..acb09a529 --- /dev/null +++ b/String/LevenshteinDistance.js @@ -0,0 +1,51 @@ +/* The Levenshtein distance (a.k.a edit distance) is a +measure of similarity between two strings. It is +defined as the minimum number of changes required to +convert string a into string b (this is done by +inserting, deleting or replacing a character in +string a). +The smaller the Levenshtein distance, +the more similar the strings are. This is a very +common problem in the application of Dynamic Programming. +*/ + +const levenshteinDistance = (a, b) => { + // Declaring array 'D' with rows = len(a) + 1 and columns = len(b) + 1: + const distanceMatrix = Array(b.length + 1) + .fill(null) + .map(() => Array(a.length + 1).fill(null)) + + // Initialising first column: + for (let i = 0; i <= a.length; i += 1) { + distanceMatrix[0][i] = i + } + + // Initialising first row: + for (let j = 0; j <= b.length; j += 1) { + distanceMatrix[j][0] = j + } + + for (let j = 1; j <= b.length; j += 1) { + for (let i = 1; i <= a.length; i += 1) { + const indicator = a[i - 1] === b[j - 1] ? 0 : 1 + // choosing the minimum of all three, vis-a-vis: + distanceMatrix[j][i] = Math.min( + distanceMatrix[j][i - 1] + 1, // deletion + distanceMatrix[j - 1][i] + 1, // insertion + distanceMatrix[j - 1][i - 1] + indicator // substitution + ) + } + } + + console.log( + 'Levenshtein Distance between ' + + a + + ' and ' + + b + + ' is = ' + + distanceMatrix[b.length][a.length] + ) + return distanceMatrix[b.length][a.length] +} + +export { levenshteinDistance } diff --git a/String/LevenshteinDistance.test.js b/String/LevenshteinDistance.test.js new file mode 100644 index 000000000..777884c36 --- /dev/null +++ b/String/LevenshteinDistance.test.js @@ -0,0 +1,26 @@ +import levenshteinDistance from './LevenshteinDistance' + +describe('levenshteinDistance', () => { + it('should calculate edit distance between two strings', () => { + expect(levenshteinDistance('', '')).toBe(0) + expect(levenshteinDistance('a', '')).toBe(1) + expect(levenshteinDistance('', 'a')).toBe(1) + expect(levenshteinDistance('abc', '')).toBe(3) + expect(levenshteinDistance('', 'abc')).toBe(3) + + // Should just add I to the beginning. + expect(levenshteinDistance('igloo', 'gloo')).toBe(1) + + // Should just substitute i with o, m with g and insert e at end + expect(levenshteinDistance('firm', 'forge')).toBe(3) + + // Should just substitute i with s, g with i, h with t and delete f from front + expect(levenshteinDistance('fighting', 'sitting')).toBe(4) + + // Should add 4 letters b, a, s and e at the beginning. + expect(levenshteinDistance('ball', 'baseball')).toBe(4) + + // Should delete 4 letters b, a, s and e at the beginning. + expect(levenshteinDistance('baseball', 'foot')).toBe(4) + }) +})