总结
这两个题和之前的公共子序列一样,都分连续不连续,
连续的->dp定义为结尾->状态来源只有一个->结果是过程中求最大或过程中记录
不连续->dp定义为范围->状态来源有两个->结果永远是dp[0][len]等这种dp数组的最终值
Leetcode647
1.问题描述
2.解决方案
a.dp的定义就是回文的定义dp[i][j]:[i,j]闭区间是否为回文子串
b.递推吧也不用多说,按照定义来就好
c.遍历顺序要以递推逻辑来定,由下图可见
d.由定义j>=i,所以遍历只遍一半就好,j从i开始
for(int i=len-1;i>=0;i--){
for(int j=i;j<=len-1;j++){
class Solution {
public:
int countSubstrings(string s) {
//1.
int len=s.size();
//2.
vector<vector<bool> > dp(len,vector<bool>(len,false));
//3.
int ans=0;
for(int i=len-1;i>=0;i--){
for(int j=i;j<=len-1;j++){
if(s[i]==s[j]){
if(j-i<=1) {dp[i][j]=true; ans++;}
if(j-i>1&&dp[i+1][j-1]==true) {dp[i][j]=true; ans++;}
}
}
}
//4.
return ans;
}
};
Leetcode5
1.问题描述
2.解决方案
1.这个题呢,一开始使用了滑动窗口方法,发现是不可以的,因为如果是滑动窗口那么是子数组局部的一个特点,而回文子串是一个整体的特点,所以不适合
2.那么使用动态规划,这个题其实和上一题 647 非常相似,首先是连续的子串,所以dp的定义是[i,j]
是否为回文串
3.所以就是在遍历的过程中,如果[i,j]是回文串,那就更新最大值,说白了就是在过程记录所以回文子串,找到最大值,这和上面的总结完全一致
4.至于递归初始化,和647完全一样,只不过647是记录数量,这道题是记录最大值
class Solution {
public String longestPalindrome(String s) {
//1.
int len=s.length();
//2.
boolean[][] dp = new boolean[len][len];
//3.
int max=-1;
int maxI=-1;
int maxJ=-1;
for(int i=len-1;i>=0;i--){
for(int j=i;j<=len-1;j++){
//如果i,j字符相等
if(s.charAt(i)==s.charAt(j)){
//如果子串长度是1或2
if(j-i<=1){
dp[i][j]=true;
if(j-i+1>max){
maxI=i;
maxJ=j;
max=j-i+1;
}
continue;
}
//如果子串长度大于2,是 3,4,5
if(dp[i+1][j-1]==true){
dp[i][j]=true;
if(j-i+1>max){
maxI=i;
maxJ=j;
max=j-i+1;
}
}else dp[i][j]=false;
}
//如果i,j字符不相等
else{
dp[i][j]=false;
}
}
}
return s.substring(maxI,maxJ+1);
}
}
Leetcode516
1.问题描述
2.解决方案
a.由于是不连续回文子序列,所以dp定义自然就是范围
b.递推
分为s[i]==s[j]那就状态来源dp[i+1][j-1],s[i]!=s[j],由于是不连续,那和之前的不连续公共子序列一个道理,自然分两个状态来源很好理解,dp[i][j]=max(dp[i+1][j],dp[i][j-1])
c.初始化
初不初都行,初始化的话,可以dp[i][i]=1
vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));
for (int i = 0; i < s.size(); i++) dp[i][i] = 1;
不初始化的话就像我这样for里面分情况讨论一下就好
if(s[i]==s[j]){
if(j==i) dp[i][j]=1;
if(j-i==1) dp[i][j]=2;
if(j-i>1) dp[i][j]=dp[i+1][j-1]+2;
}
d.遍历顺序依然按递推逻辑
class Solution {
public:
int longestPalindromeSubseq(string s) {
//1.
int len=s.size();
//2.
vector<vector<int> > dp(len,vector<int>(len,0));
//3.
for(int i=len-1;i>=0;i--){
for(int j=i;j<=len-1;j++){
if(s[i]==s[j]){
if(j==i) dp[i][j]=1;
if(j-i==1) dp[i][j]=2;
if(j-i>1) dp[i][j]=dp[i+1][j-1]+2;
}
if(s[i]!=s[j]){
dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
}
}
}
//4.
return dp[0][len-1];
}
};
Java版本
class Solution {
public int longestPalindromeSubseq(String s) {
//1.
int len = s.length();
int[][] dp = new int[len][len];
for(int i=0;i<len;i++) dp[i][i] = 1;
//2.
for(int i=len-1;i>=0;i--){
for(int j=i+1;j<len;j++){
if(s.charAt(i)==s.charAt(j)){
// 可以不分类,因为如果j<i dp[i][j] = 0 所以也就没必要分情况
// if(i+1==j) dp[i][j] = 2;
// else dp[i][j] = dp[i+1][j-1] + 2;
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][len-1];
}
}