问题描述
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

题解
定义状态(定义子问题)
假设字符串 text1和text2 的长度分别为 m和n
dp[i][j]:表示text1[0,i]字符和text2[0,j]字符之间的最长公共子序列;
i=0,text1为空,空字符串和任何字符串的最长公共子序列都为0,dp[0][j]=0;
j=0,text2为空,空字符串和任何字符串的最长公共子序列都为0,dp[i][0]=0;
状态转移方程(描述子问题之间的联系,分类讨论)
下标从0开始
text1[i-1]:第i个字符;
text2[j-1]:第j个字符;
考虑子问题之间的关系,开始分类讨论
当 text1[i-1] == text2[j-1]时:
基于text1[0,i-1]字符和text2[0,j-1]字符的最长公共子序列(前一个最优子问题)考虑,再增加一个字符(公共字符)。
因此 dp[i][j] = dp[i - 1][j - 1] + 1
当 text1[i-1] != text2[j-1]时,考虑两种情况:
前一个子问题已最优,基于前一个子问题,当前只需考虑增加一个字符后的各种情况;
text1[0,i-1]字符和text2[0,j]的最长公共子序列;
text1[0,i]字符和text2[0,j-1]的最长公共子序列;
因为要得到最长公共子序列,所以取最大的。
因此 dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])
所以状态转移方程可以描述为:
dp[i][j]={dp[i−1][j−1]+1,max(dp[i−1][j],dp[i][j−1]),text1[i−1]=text2[j−1]text1[i−1]=text2[j−1]
最终计算得到dp[m][n]即为text1和text2的最长公共子序列的长度。
代码
public static int solution(String text1, String text2) {
int len1 = text1.length()
int len2 = text2.length()
// dp初始化为0
int[][] dp = new int[len1 + 1][len2 + 1]
for (int i = 1
for (int j = 1
// 三种情况
if (text1.charAt(i - 1) == text2.charAt(j - 1)) { // 相等一种
dp[i][j] = dp[i - 1][j - 1] + 1
} else { // 不相等两种,取最大
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])
}
}
}
return dp[len1][len2]
}