题目链接
思路
- 这道题前面都是做的单序列的题目,也就是说输入的内容是一个数组或者是字符串。现在以及后面的几道题都是双序列,也就是说要处理的数据有两个数组或者字符串,对于双序列的题目,一般的状态转移方程有两个参数,因此我们需要找到f(i,j)和f(i-1,j-1)、f(i-1,j)、f(i,j-1)的关系
- 假设f(i,j)是s1的前i个字符和s2的前j个字符可以形成的最大公共序列,那么最终的结果即为求f(s1.length(),s2.length())
- 首先找递推关系(这里书上讲的很清楚)
- 如果chi = chj 那么有 f(i,j)=f(i-1,j-1)+1
- 如果chi != chj 那么有 f(i,j)=max{f(i-1,j),f(i,j-1)} (因为此时chi和chj一定不能同时出现在共同子序列中)
- 解决了递归式后还需要处理边界值,可以发现f(i,0)和f(i-1,-1)有关、f(0,j)和f(-1,j-1)有关,也就是说我们在从小到大填充数组内容时还需要先计算-1的值,具体到答案数组中我们可以额外增添一列,这样可以简化我们代码的书写
- 首先有f(-1,-1)是0,这里要联系f(i,j)的意义,即s1的前i个字符和s2的前j个字符可以形成的最大公共序列,那么前-1个字符形成的最大公共子序列自然是0,同理f(-1,j)和f(i,-1)自然也全都是0
- 最后一点 这个题可以进行状态压缩,因为f(i,j)在计算时之和他左边相邻、上面相邻、左上相邻的三个数有关,所以可以只用2行来保存即可
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int[][] dp = new int[2][text2.length()+1];
for(int i = 0 ;i < text1.length();i++){
for(int j = 0 ;j < text2.length();j++){
if(text1.charAt(i) == text2.charAt(j))
dp[(i+1)%2][j+1] = dp[(i)%2][j] + 1;
else
dp[(i+1)%2][j+1] = Math.max(dp[(i)%2][j+1],dp[(i+1)%2][j]);
}
}
return dp[text1.length()%2][text2.length()];
}
}