fn longest_common_substring(s1: &str, s2: &str) -> usize { let bytes1 = s1.as_bytes(); let bytes2 = s2.as_bytes(); let mut max_len = 0; let mut dp = vec![vec![0; bytes2.len() + 1]; bytes1.len() + 1]; for i in 1..=bytes1.len() { for j in 1..=bytes2.len() { if bytes1[i - 1] == bytes2[j - 1] { dp[i][j] = dp[i - 1][j - 1] + 1; if dp[i][j] > max_len { max_len = dp[i][j]; } } } } max_len } fn main() { let s1 = "ababc"; let s2 = "babca"; println!("{}", longest_common_substring(s1, s2)); }
The longest common substring between "ababc" and "babca" is "bab" which has length 3.
The code uses a 2D table to track matching characters and updates the maximum length found.
Each dp[i][j] stores the length of the longest common substring that ends exactly at s1[i-1] and s2[j-1].
This helps to extend substrings character by character.
fn longest_common_substring(s1: &str, s2: &str) -> usize { let bytes1 = s1.as_bytes(); let bytes2 = s2.as_bytes(); let mut max_len = 0; let mut dp = vec![vec![0; bytes2.len()]; bytes1.len()]; for i in 1..=bytes1.len() { for j in 1..=bytes2.len() { if bytes1[i - 1] == bytes2[j - 1] { dp[i][j] = dp[i - 1][j - 1] + 1; if dp[i][j] > max_len { max_len = dp[i][j]; } } } } max_len } fn main() { let s1 = "abc"; let s2 = "abc"; println!("{}", longest_common_substring(s1, s2)); }
The dp vector is initialized with size bytes1.len() x bytes2.len(), but the loops access dp[i][j] where i and j go up to bytes1.len() and bytes2.len() inclusive.
This causes an index out of bounds panic at runtime.
Original s2 ends with "abcde" matching s1's start, length 5.
After changing last character to 'f', the common substring is "abcd" of length 4.
The algorithm uses a 2D table of size m x n and fills each cell once.
Thus, the time complexity is O(m * n).
