- 给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。
- 子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
- 解法一、 #样本对应模型
- str和str逆找最长公共子序列=》最长回文子序列
- 解法二、 #范围尝试模型
- 思路:L~R范围内的最长回文子序列只有三种可能。不算左端,不算右端,不算左右端(一定<=不算单端),左右端都算(要求左右端相等)
- base case:只有一个时len=1
- 有两个时,两相等为2,不等为1
- 思路:L和R是/否为子序列中一个,一共4中情况
-
int p1 = f(str, L + 1, R - 1);
int p2 = f(str, L, R - 1);
int p3 = f(str, L + 1, R);
int p4 = str[L] != str[R] ? 0 : (2 + f(str, L + 1, R - 1));
- 普遍依赖:左,左下,右
- 优化:不考虑p1情况
![在这里插入图片描述](https://img-blog.csdnimg.cn/80fafe25ca2e4ae2985c5dcb876014f1.png)
public static int longestCommonSubsequence(char[] str1, char[] str2) {
int N = str1.length;
int M = str2.length;
int[][] dp = new int[N][M];
dp[0][0] = str1[0] == str2[0] ? 1 : 0;
for (int i = 1; i < N; i++) {
dp[i][0] = str1[i] == str2[0] ? 1 : dp[i - 1][0];
}
for (int j = 1; j < M; j++) {
dp[0][j] = str1[0] == str2[j] ? 1 : dp[0][j - 1];
}
for (int i = 1; i < N; i++) {
for (int j = 1; j < M; j++) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
if (str1[i] == str2[j]) {
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 1] + 1);
}
}
}
return dp[N - 1][M - 1];
}