价值:记录学习过程的思考,本身就是一场动态规划的前生,记忆化搜索。
Problem: 516. 最长回文子序列
//f[i][j] = [i~j] 最长的回文子序列
//分类
//如果1: arr[i] == arr[j] ; f[i][j] = f[i+1][j-1]+2
//如果2: arr[i] != arr[j] ; f[i][j] = max(f[i+1][j],f[i][j-1]) //(左边在结果集或右边在结果集, 取max)
//取答案:max每个分类的结果:f[i][j] = max(f[i+1][j-1]+2, max(f[i+1][j],f[i][j-1]))
class Solution {
public int longestPalindromeSubseq(String s) {
char[] arr = s.toCharArray();
// f[i][j] = i~j最长的回文子序列
// arr[i] == arr[j] ; f[i][j] = f[i+1][j-1]+2
// arr[i] != arr[j] ; f[i][j] = max(f[i+1][j],f[i][j-1])
// f[i][j] = max(f[i+1][j-1]+2,max(f[i+1][j],f[i][j-1]))
int n = arr.length;
int[][] dp = new int[n][n];
// 【j : 0 ~ n-1】
// 起点 ->【j,j】->扩展 [j,j+1] -> 扩展 [j-1,j+1]
// i 往左边走, j 往右边走,
// init:j = 0 ,i = j-1 ;
// 顺序 整体上从左往右遍历
for (int j = 0; j < n; j++) {
// 递归边界 dfs(j,j) = 1
dp[j][j] = 1;
// (j+1,j)交叉 i = j+1 ,dfs(j+1,j) = 0,这里就是为什么i从j-1开始
for (int i = j - 1; i >= 0; i--) {
if (arr[i] == arr[j]) {
dp[i][j] = dp[i + 1][j - 1] + 2;
} else {
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
return dp[0][n - 1];
}
public int longestPalindromeSubseq1(String s) {
char[] arr = s.toCharArray();
// f[i][j] = i~j最长的回文子序列
// arr[i] == arr[j] ; f[i][j] = f[i+1][j-1]+2
// arr[i] != arr[j] ; f[i][j] = max(f[i+1][j],f[i][j-1])
// f[i][j] = max(f[i+1][j-1]+2,max(f[i+1][j],f[i][j-1]))
int n = arr.length;
int[][] dp = new int[n][n];
// 【i : n-1 ~ 0】
// 起点 ->【i,i】->扩展 [i,j] -> 扩展 [i-1,j+1]
// i 往左边走, j 往右边走,
// init: i = n-1, j = i+1,
// 顺序 整体上从右往左遍历
for (int i = n - 1; i >= 0; i--) {
// 递归边界 dfs(i,i) = 1
dp[i][i] = 1;
//(i,i-1)交叉:j = i-1 : dfs(i,i-1) = 0,这里就是为什么j从i+1开始
for (int j = i + 1; j < n; j++) {
if (arr[i] == arr[j]) {
dp[i][j] = dp[i + 1][j - 1] + 2;
} else {
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
return dp[0][n - 1];
}
}