pub fn lcs_length(a: &str, b: &str) -> usize {
let a_chars: Vec<char> = a.chars().collect();
let b_chars: Vec<char> = b.chars().collect();
let m = a_chars.len();
let n = b_chars.len();
let mut dp = vec![vec![0; n + 1]; m + 1];
for i in 1..=m {
for j in 1..=n {
if a_chars[i - 1] == b_chars[j - 1] {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = dp[i - 1][j].max(dp[i][j - 1]);
}
}
}
dp[m][n]
}
pub fn lcs_sequence(a: &str, b: &str) -> String {
let a_chars: Vec<char> = a.chars().collect();
let b_chars: Vec<char> = b.chars().collect();
let m = a_chars.len();
let n = b_chars.len();
let mut dp = vec![vec![0; n + 1]; m + 1];
for i in 1..=m {
for j in 1..=n {
if a_chars[i - 1] == b_chars[j - 1] {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = dp[i - 1][j].max(dp[i][j - 1]);
}
}
}
let mut i = m;
let mut j = n;
let mut subsequence = Vec::new();
while i > 0 && j > 0 {
if a_chars[i - 1] == b_chars[j - 1] {
subsequence.push(a_chars[i - 1]);
i -= 1;
j -= 1;
} else if dp[i - 1][j] > dp[i][j - 1] {
i -= 1;
} else {
j -= 1;
}
}
subsequence.reverse();
subsequence.into_iter().collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lcs_length() {
assert_eq!(lcs_length("", ""), 0);
assert_eq!(lcs_length("ABC", ""), 0);
assert_eq!(lcs_length("", "ABC"), 0);
assert_eq!(lcs_length("ABCBDAB", "BDCABA"), 4);
assert_eq!(lcs_length("XMJYAUZ", "MZJAWXU"), 4);
assert_eq!(lcs_length("BANANA", "ATANA"), 4);
}
#[test]
fn test_lcs_sequence() {
assert_eq!(lcs_sequence("", ""), "");
assert_eq!(lcs_sequence("ABC", ""), "");
assert_eq!(lcs_sequence("", "ABC"), "");
let seq1 = lcs_sequence("ABCBDAB", "BDCABA");
assert_eq!(seq1.len(), 4);
let seq2 = lcs_sequence("XMJYAUZ", "MZJAWXU");
assert_eq!(seq2.len(), 4);
assert!(is_subsequence(&seq2, "XMJYAUZ"));
assert!(is_subsequence(&seq2, "MZJAWXU"));
}
fn is_subsequence(subseq: &str, s: &str) -> bool {
let mut it = s.chars();
for c in subseq.chars() {
match it.find(|&x| x == c) {
Some(_) => continue,
None => return false,
}
}
true
}
}