最长公共子序列
2024年7月29日约 431 字大约 1 分钟
最长公共子序列
题意
给定两个字符串 s1 和 s2,返回这两个字符串的最长公共子序列的长度。如果不存在公共子序列,返回 0
。
一个字符串的子序列是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
- 例如,
"ace"
是"abcde"
的子序列,但"aec"
不是"abcde"
的子序列。
两个字符串的公共子序列是这两个字符串所共同拥有的子序列。
思路
用两个指针 , 在两个字符串上游走,这就是「状态」,字符串中的每个字符都有两种「选择」,要么在 lcs 中,要么不在。
f[i][j]
的含义是:对于 s1[1..i]
和 s2[1..j]
,它们的 LCS 长度是 f[i][j]
。
代码
class Solution {
public int longestCommonSubsequence(String s1, String s2) {
// 定义:s1[0..i-1] 和 s2[0..j-1] 的 lcs 长度为 f[i][j]
// 目标:s1[0..n-1] 和 s2[0..m-1] 的 lcs 长度,即 f[n][m]
int n = s1.length(), m = s2.length();
// 初始化:f[0][..] = f[..][0] = 0
int f[][] = new int[n + 1][m + 1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
// s1[i-1] 和 s2[j-1] 至少有一个不在 lcs 中
f[i][j] = Math.max(f[i][j - 1], f[i - 1][j]);
// 因为 i 和 j 从 1 开始,所以要减一
if (s1.charAt(i - 1) == s2.charAt(j - 1))
// s1[i-1] 和 s2[j-1] 必然在 lcs 中
f[i][j] = Math.max(f[i][j], f[i - 1][j - 1] + 1);
}
}
return f[n][m];
}
}