Skip to content

Commit 12f2764

Browse files
authored
Improve Longest Common Substring Implementation (TheAlgorithms#801)
ref: improve longest common substring implementation
1 parent 296e610 commit 12f2764

File tree

1 file changed

+52
-37
lines changed

1 file changed

+52
-37
lines changed
Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,36 @@
1-
// Longest common substring via Dynamic Programming
2-
// longest_common_substring(a, b) returns the length of longest common substring between the strings a and b.
3-
pub fn longest_common_substring(text1: &str, text2: &str) -> i32 {
4-
let m = text1.len();
5-
let n = text2.len();
1+
//! This module provides a function to find the length of the longest common substring
2+
//! between two strings using dynamic programming.
63
7-
let t1 = text1.as_bytes();
8-
let t2 = text2.as_bytes();
4+
/// Finds the length of the longest common substring between two strings using dynamic programming.
5+
///
6+
/// The algorithm uses a 2D dynamic programming table where each cell represents
7+
/// the length of the longest common substring ending at the corresponding indices in
8+
/// the two input strings. The maximum value in the DP table is the result, i.e., the
9+
/// length of the longest common substring.
10+
///
11+
/// The time complexity is `O(n * m)`, where `n` and `m` are the lengths of the two strings.
12+
/// # Arguments
13+
///
14+
/// * `s1` - The first input string.
15+
/// * `s2` - The second input string.
16+
///
17+
/// # Returns
18+
///
19+
/// Returns the length of the longest common substring between `s1` and `s2`.
20+
pub fn longest_common_substring(s1: &str, s2: &str) -> usize {
21+
let mut substr_len = vec![vec![0; s2.len() + 1]; s1.len() + 1];
22+
let mut max_len = 0;
923

10-
// BottomUp Tabulation
11-
let mut dp = vec![vec![0; n + 1]; m + 1];
12-
let mut ans = 0;
13-
for i in 1..=m {
14-
for j in 1..=n {
15-
if t1[i - 1] == t2[j - 1] {
16-
dp[i][j] = 1 + dp[i - 1][j - 1];
17-
ans = std::cmp::max(ans, dp[i][j]);
24+
s1.as_bytes().iter().enumerate().for_each(|(i, &c1)| {
25+
s2.as_bytes().iter().enumerate().for_each(|(j, &c2)| {
26+
if c1 == c2 {
27+
substr_len[i + 1][j + 1] = substr_len[i][j] + 1;
28+
max_len = max_len.max(substr_len[i + 1][j + 1]);
1829
}
19-
}
20-
}
30+
});
31+
});
2132

22-
ans
33+
max_len
2334
}
2435

2536
#[cfg(test)]
@@ -28,28 +39,32 @@ mod tests {
2839

2940
macro_rules! test_longest_common_substring {
3041
($($name:ident: $inputs:expr,)*) => {
31-
$(
32-
#[test]
33-
fn $name() {
34-
let (text1, text2, expected) = $inputs;
35-
assert_eq!(longest_common_substring(text1, text2), expected);
36-
assert_eq!(longest_common_substring(text2, text1), expected);
37-
}
38-
)*
42+
$(
43+
#[test]
44+
fn $name() {
45+
let (s1, s2, expected) = $inputs;
46+
assert_eq!(longest_common_substring(s1, s2), expected);
47+
assert_eq!(longest_common_substring(s2, s1), expected);
48+
}
49+
)*
3950
}
4051
}
4152

4253
test_longest_common_substring! {
43-
empty_inputs: ("", "", 0),
44-
one_empty_input: ("", "a", 0),
45-
single_same_char_input: ("a", "a", 1),
46-
single_different_char_input: ("a", "b", 0),
47-
regular_input_0: ("abcdef", "bcd", 3),
48-
regular_input_1: ("abcdef", "xabded", 2),
49-
regular_input_2: ("GeeksforGeeks", "GeeksQuiz", 5),
50-
regular_input_3: ("abcdxyz", "xyzabcd", 4),
51-
regular_input_4: ("zxabcdezy", "yzabcdezx", 6),
52-
regular_input_5: ("OldSite:GeeksforGeeks.org", "NewSite:GeeksQuiz.com", 10),
53-
regular_input_6: ("aaaaaaaaaaaaa", "bbb", 0),
54+
test_empty_strings: ("", "", 0),
55+
test_one_empty_string: ("", "a", 0),
56+
test_identical_single_char: ("a", "a", 1),
57+
test_different_single_char: ("a", "b", 0),
58+
test_common_substring_at_start: ("abcdef", "abc", 3),
59+
test_common_substring_at_middle: ("abcdef", "bcd", 3),
60+
test_common_substring_at_end: ("abcdef", "def", 3),
61+
test_no_common_substring: ("abc", "xyz", 0),
62+
test_overlapping_substrings: ("abcdxyz", "xyzabcd", 4),
63+
test_special_characters: ("@abc#def$", "#def@", 4),
64+
test_case_sensitive: ("abcDEF", "ABCdef", 0),
65+
test_full_string_match: ("GeeksforGeeks", "GeeksforGeeks", 13),
66+
test_substring_with_repeated_chars: ("aaaaaaaaaaaaa", "aaa", 3),
67+
test_longer_strings_with_common_substring: ("OldSite:GeeksforGeeks.org", "NewSite:GeeksQuiz.com", 10),
68+
test_no_common_substring_with_special_chars: ("!!!", "???", 0),
5469
}
5570
}

0 commit comments

Comments
 (0)