最长公共子序列

  1. /// Longest common subsequence via Dynamic Programming
  2. /// longest_common_subsequence(a, b) returns the longest common subsequence
  3. /// between the strings a and b.
  4. pub fn longest_common_subsequence(a: &str, b: &str) -> String {
  5. let a: Vec<_> = a.chars().collect();
  6. let b: Vec<_> = b.chars().collect();
  7. let (na, nb) = (a.len(), b.len());
  8. // solutions[i][j] is the length of the longest common subsequence
  9. // between a[0..i-1] and b[0..j-1]
  10. let mut solutions = vec![vec![0; nb + 1]; na + 1];
  11. for (i, ci) in a.iter().enumerate() {
  12. for (j, cj) in b.iter().enumerate() {
  13. // if ci == cj, there is a new common character;
  14. // otherwise, take the best of the two solutions
  15. // at (i-1,j) and (i,j-1)
  16. solutions[i + 1][j + 1] = if ci == cj {
  17. solutions[i][j] + 1
  18. } else {
  19. solutions[i][j + 1].max(solutions[i + 1][j])
  20. }
  21. }
  22. }
  23. // reconstitute the solution string from the lengths
  24. let mut result: Vec<char> = Vec::new();
  25. let (mut i, mut j) = (na, nb);
  26. while i > 0 && j > 0 {
  27. if a[i - 1] == b[j - 1] {
  28. result.push(a[i - 1]);
  29. i -= 1;
  30. j -= 1;
  31. } else if solutions[i - 1][j] > solutions[i][j - 1] {
  32. i -= 1;
  33. } else {
  34. j -= 1;
  35. }
  36. }
  37. result.reverse();
  38. result.iter().collect()
  39. }
  40. #[cfg(test)]
  41. mod tests {
  42. use super::longest_common_subsequence;
  43. #[test]
  44. fn test_longest_common_subsequence() {
  45. // empty case
  46. assert_eq!(&longest_common_subsequence("", ""), "");
  47. assert_eq!(&longest_common_subsequence("", "abcd"), "");
  48. assert_eq!(&longest_common_subsequence("abcd", ""), "");
  49. // simple cases
  50. assert_eq!(&longest_common_subsequence("abcd", "c"), "c");
  51. assert_eq!(&longest_common_subsequence("abcd", "d"), "d");
  52. assert_eq!(&longest_common_subsequence("abcd", "e"), "");
  53. assert_eq!(&longest_common_subsequence("abcdefghi", "acegi"), "acegi");
  54. // less simple cases
  55. assert_eq!(&longest_common_subsequence("abcdgh", "aedfhr"), "adh");
  56. assert_eq!(&longest_common_subsequence("aggtab", "gxtxayb"), "gtab");
  57. // unicode
  58. assert_eq!(
  59. &longest_common_subsequence("你好,世界", "再见世界"),
  60. "世界"
  61. );
  62. }
  63. }