动态规划五部曲:
1、确定dp数组及其下标含义
dp[i][j]:区间范围[i,j]内的子串是否是回文串,是为true,否为false
2、确定递推式
s[i] != s[j] dp[i][j] = false;
s[i]==s[j],i=j,dp[i][j]=true
s[i]==s[j],|i-j|=1,aa dp[i][j]=true
s[i]==s[j],|i-j|>1 aba if(dp[i+1][j-1]==true) dp[i][j]=true,否则 dp[i][j] = false
3、初始化
初始化为false
4、确定遍历顺序
dp[i+1][j-1] 情况三中该值决定dp[i][j],dp[i+1][j-1]在其左下角
所以遍历顺序 从下到上 从左到右
5、举例推导dp数组
"abc"
dp:
1 0 0
0 1 0
0 0 1
题解:
class Solution {
public:
int countSubstrings(string s) {
//dp[i][j]:区间范围[i,j]内的子串是否是回文串,是为true,否为false
//确定递推公式
//s[i] != s[j] dp[i][j] = false;
//s[i]==s[j],i=j,dp[i][j]=true
//s[i]==s[j],|i-j|=1,aa dp[i][j]=true
//s[i]==s[j],|i-j|>1 aba if(dp[i+1][j-1]==true) dp[i][j]=true,否则 dp[i][j] = false
//定义dp数组
vector<vector<bool>> dp(s.length(),vector<bool>(s.length(),false));
//结果
int result = 0;
//遍历顺序 从下到上 从左到右 j>i
for(int i=s.length()-1;i>=0;i--){
for(int j = i;j<s.length();j++){
if(s[i]==s[j]){
if(j-i<=1){
dp[i][j] = true;
result++;
}else if(dp[i+1][j-1]){
dp[i][j] = true;
result++;
}
}
}
}
return result;
}
};
双指针法:
class Solution {
public:
int countSubstrings(string s) {
int result = 0;
for(int i = 0;i<s.length();i++){
//以i为中心
result+=extend(s,i,i,s.length());
//以i和i+1为中心
result+=extend(s,i,i+1,s.length());
}
return result;
}
//以i或者以i和i+1为中心点的回文串
int extend(string &s,int i,int j,int n){
int res = 0;
while(i>=0&&j<n&&s[i]==s[j]){
//相等 往外扩
i--;
j++;
res++;
}
return res;
}
};