一、题目打卡
1.1 回文子串
题目链接:. - 力扣(LeetCode)
class Solution {
public:
int countSubstrings(string s) {
// vector<bool> dp;
// // 这里想在初始化之外进行构造,就需要使用 assign 函数
// if(s.size()&1 == 0) dp.assign(s.size()/2,false);
// else dp.assign(s.size()/2+1,false);
// if(s.size()&1 == 1) dp[0] = true;
// else{
// if(s[s.size()/2 - 1] == s[s.size()]) dp[0] = true;
// }
// for(int i = 1, j = s.size()&1 ? :s.size()/2+1)
// return 1;
// 在[i,j]之间的子串是不是回文串
vector<vector<bool>> dp(s.size(),vector<bool>(s.size(), false));
int res= 0;
// 这里因为取值的时候是从左下转移过来的,所以不能从前向后遍历,不然的话会取到的值可能是错的
for(int i = s.size() - 1; i >= 0;i--){
// for(int i = 0; i < s.size();i++){
for(int j = i; j < s.size();j++){
if(s[i] == s[j]){
if(j - i <= 1){
dp[i][j] = true;
res++;
}
else{
if(dp[i+1][j - 1]){
dp[i][j] = true;
res++;
}
}
}
}
}
for(int i = 0 ; i < s.size();i++){
for(int j = 0; j < s.size();j++){
cout << dp[i][j] << " ";
}
cout << endl;
}
return res;
}
};
这里和之前动态规划类题目都不太一样,这个题目的dp数字的定义主要是考虑了回文这个结构的特殊性,直接看的答案解析,看懂了其实再来理解这个题目就不是很难了。
动态规划转移的方程,重要的是要理解为什么这个转移的方向来自左下角,这也决定了后面的遍历顺序,必须是从i的最后面向前遍历,否则就会是没有填充的数值进行的递推。
1.2 最长的回文子串
题目链接:. - 力扣(LeetCode)
class Solution {
public:
int longestPalindromeSubseq(string s) {
// [i,j]之间最长的回文子序列
vector<vector<int>> dp(s.size(),vector<int>(s.size(), 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) dp[i][j] = 1;
else if(j - i == 1) dp[i][j] = 2;
else dp[i][j] = dp[i + 1][j - 1] + 2;
}
else dp[i][j] = max({dp[i + 1][j - 1], dp[i][j-1], dp[i+1][j]});
}
}
// for(int i = 0; i < s.size();i++){
// for(int j = 0 ; j< s.size();j++){
// cout << dp[i][j] << " ";
// }
// cout << endl;
// }
return dp[0][s.size() - 1];
}
};
和上面的题目稍微有一点区别,但是转移的思路其实还是一致的,主要在于处理递推的时候,需要注意当前两个指针不相等的时候,递推的方法就需要对之前的内容进行处理。