From 1eb9a5692ce82a2f4f3b2444eafc6f7638d734f8 Mon Sep 17 00:00:00 2001 From: "pranav.date" Date: Mon, 13 Oct 2025 11:07:17 +0530 Subject: [PATCH] Add contributions for a pull request: Done (two new files added). Ensure tests/build: Attempted but blocked due to missing Maven in this environment (reported). --- .../strings/LevenshteinDistance.java | 44 +++++++++++++++++++ .../strings/LevenshteinDistanceTest.java | 32 ++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 src/main/java/com/thealgorithms/strings/LevenshteinDistance.java create mode 100644 src/test/java/com/thealgorithms/strings/LevenshteinDistanceTest.java diff --git a/src/main/java/com/thealgorithms/strings/LevenshteinDistance.java b/src/main/java/com/thealgorithms/strings/LevenshteinDistance.java new file mode 100644 index 000000000000..9399621444b9 --- /dev/null +++ b/src/main/java/com/thealgorithms/strings/LevenshteinDistance.java @@ -0,0 +1,44 @@ +package com.thealgorithms.strings; + +/** + * Computes the Levenshtein distance (edit distance) between two strings. + * Time: O(n*m), Space: O(min(n, m)) if optimized, here using full DP for simplicity. + */ +public final class LevenshteinDistance { + private LevenshteinDistance() {} + + /** + * Compute the edit distance between s and t. + * + * @param s first string (may be null) + * @param t second string (may be null) + * @return minimum number of single-character edits (insertions, deletions or substitutions) + */ + public static int compute(final String s, final String t) { + if (s == null) return t == null ? 0 : t.length(); + if (t == null) return s.length(); + final int n = s.length(); + final int m = t.length(); + + if (n == 0) return m; + if (m == 0) return n; + + int[][] dp = new int[n + 1][m + 1]; + + for (int i = 0; i <= n; i++) dp[i][0] = i; + for (int j = 0; j <= m; j++) dp[0][j] = j; + + for (int i = 1; i <= n; i++) { + char cs = s.charAt(i - 1); + for (int j = 1; j <= m; j++) { + char ct = t.charAt(j - 1); + int cost = (cs == ct) ? 0 : 1; + dp[i][j] = Math.min(Math.min(dp[i - 1][j] + 1, // deletion + dp[i][j - 1] + 1), // insertion + dp[i - 1][j - 1] + cost); // substitution + } + } + + return dp[n][m]; + } +} diff --git a/src/test/java/com/thealgorithms/strings/LevenshteinDistanceTest.java b/src/test/java/com/thealgorithms/strings/LevenshteinDistanceTest.java new file mode 100644 index 000000000000..0d8bac1d7dc0 --- /dev/null +++ b/src/test/java/com/thealgorithms/strings/LevenshteinDistanceTest.java @@ -0,0 +1,32 @@ +package com.thealgorithms.strings; + +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + +public class LevenshteinDistanceTest { + + @Test + void sameStringsHaveZeroDistance() { + assertThat(LevenshteinDistance.compute("test", "test")).isZero(); + } + + @Test + void emptyToNonEmpty() { + assertThat(LevenshteinDistance.compute("", "abc")).isEqualTo(3); + assertThat(LevenshteinDistance.compute("abc", "")).isEqualTo(3); + } + + @Test + void nullHandling() { + assertThat(LevenshteinDistance.compute(null, null)).isZero(); + assertThat(LevenshteinDistance.compute(null, "abc")).isEqualTo(3); + assertThat(LevenshteinDistance.compute("abc", null)).isEqualTo(3); + } + + @Test + void typicalExamples() { + assertThat(LevenshteinDistance.compute("kitten", "sitting")).isEqualTo(3); + assertThat(LevenshteinDistance.compute("flaw", "lawn")).isEqualTo(2); + assertThat(LevenshteinDistance.compute("gumbo", "gambol")).isEqualTo(2); + } +}