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.
6
3
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 ;
9
23
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 ] ) ;
18
29
}
19
- }
20
- }
30
+ } ) ;
31
+ } ) ;
21
32
22
- ans
33
+ max_len
23
34
}
24
35
25
36
#[ cfg( test) ]
@@ -28,28 +39,32 @@ mod tests {
28
39
29
40
macro_rules! test_longest_common_substring {
30
41
( $( $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
+ ) *
39
50
}
40
51
}
41
52
42
53
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 ) ,
54
69
}
55
70
}
0 commit comments