Day49:647. 回文子串、516.最长回文子序列
文章目录
- 647. 回文子串
- 思路
- 代码实现
- 516.最长回文子序列
- 思路
- 代码实现
647. 回文子串
题目链接
思路
- 确定dp数组(dp table)以及下标的含义
布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false。 - 确定递推公式
s[i]!=s[j],dp[i][j]一定是false;
s[i]=s[j],有如下三种情况:
情况一:下标i 与 j相同,同一个字符是回文子串
情况二:下标i 与 j相差为1,例如aa也是回文子串
情况三:下标i 与 j相差大于1的时候,例如cabac,此时s[i]与s[j]已经相同了,我们看i到j区间是不是回文子串就看aba是不是回文就可以了,那么aba的区间就是 i+1 与 j-1区间,这个区间是不是回文就看dp[i + 1][j - 1]是否为true。 - dp数组如何初始化
所以dp[i][j]初始化为false。 - 确定遍历顺序
情况三是根据dp[i + 1][j - 1]是否为true,在对dp[i][j]进行赋值true
所以一定要从下到上,从左到右遍历,这样保证dp[i + 1][j - 1]都是经过计算的 - 举例推导dp数组
代码实现
class Solution {
public:
int countSubstrings(string s) {
vector<vector<bool>> dp(s.size(),vector<bool>(s.size(),false));
int result=0;
for(int i=s.size()-1;i>=0;i--){
for(int j=i;j<s.size();j++){
if(s[i]==s[j]){
if(j-i<=1){
dp[i][j]=true;
result++;
}
else if(dp[i+1][j-1]==true){
dp[i][j]=true;result++;
}
}
}
}
return result;
}
};
516.最长回文子序列
题目链接
思路
其他的和上一题一样,就是递推公式不同
- 情况一:s[i]=s[j],dp[i][j]=dp[i+1][j-1]+2;
- 情况一:s[i]!=s[j],dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
如果s[i]与s[j]不相同,说明s[i]和s[j]的同时加入 并不能增加[i,j]区间回文子序列的长度,那么分别加入s[i]、s[j]看看哪一个可以组成最长的回文子序列
代码实现
class Solution {
public:
int longestPalindromeSubseq(string s) {
vector<vector<int>> dp(s.size(),vector<int>(s.size(),0));
for(int i=0;i<s.size();i++)dp[i][i]=1;
for(int i=s.size()-1;i>=0;i--){
for(int j=i+1;j<s.size();j++){
if(s[i]==s[j]){
dp[i][j]=dp[i+1][j-1]+2;
}
else dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
}
}
return dp[0][s.size()-1];
}
};