动态规划
647.回文子串
解题思路: 注意解决回文问题时,需要从内向外考虑, 考虑dp[i][j]的值根据dp[i+1][j-1]来推导
dp[i][j]: 代表s以i开始, 以j结束的区间内回文子串的数量- 当两个点字符相等时:
- 若内部是回文子串, 则回文子串数量 + 1, 同时记录回文子串
- 若内部不是回文子串, 则数量不变, 且回文子串标志置为
false
- 考虑
dp[i][j]的值根据dp[i+1][j-1]来推导, 所以dp数组必须是从左到右, 从下到上遍历, 即i逆序, j升序
代码:
class Solution {
public int countSubstrings(String s) {
int n = s.length();
// dp[i][j]: 代表s以i开始, 以j结束的区间内回文子串的数量
boolean[][] dp = new boolean[n][n];
int res = 0;
// 从O(n^3) 优化为 O(n^2) --- 注意递推公式(逆序)
for(int i=n-1; i >= 0; i--){
for(int j=i; j < n; j++){
if(s.charAt(i) == s.charAt(j) && (j - i < 2 || dp[i+1][j-1])){
dp[i][j] = true;
res++;
}
}
}
return res;
}
}
516.最长回文子序列
解题思路: 从内向外考虑
- 若
s[i] == s[j]:则最长回文子序列的长度 需要 +2 - 若若
s[i] != s[j]:则等于将左边字符进行匹配或者右边字符进行匹配时的最长序列 最大值(因为之前都计算过)
代码:
class Solution {
// 求最长回文子序列, 类似于求最长单调递增子序列 --- 求最长单调递增子数组
public int longestPalindromeSubseq(String s) {
int n = s.length();
int[][] dp = new int[n][n];
for(int i=0; i<n; i++) dp[i][i] = 1;
int ans = 0;
for(int i=n-1; i>=0; i--){
for(int j=i + 1; j < n; j++){
if(s.charAt(i) == s.charAt(j)){
dp[i][j] = dp[i+1][j-1] + 2;
}else{
dp[i][j] = Math.max(dp[i][j-1], dp[i+1][j]);
}
}
}
return dp[0][n-1];
}
}