参考:https://www.cnblogs.com/AlvinZH/p/8527668.html
回文串特点:以中间的一个(奇数个)或者两个(偶数个)字母为中心是对称的
1.动态规划
dp[i][j]
表示i—j之间的序列是否是回文串,如果是为True否则为False,那么递推公式为:
(1)如果s[i] != s[j]
那么就不是回文串
(2)如果s[i] == s[j]
那么 dp[i][j] = dp[i+1][j-1]
公式含义为:如果i+1到j-1的序列是回文串,且s[i] == s[j]
那么说明i到j也是回文串,如果i+1到j-1不是回文串,那么i到j也不是回文串
上述公式要成立需要满足:i+1<j-1
,即j-i>2
那么考虑j-i<=2
的情况:
1.j-i=0,即j=i,即一个字母本身他就是回文串
2.j-i=1,即i,j相邻,且两个字母相等s[i]=s[j],那么也是回文串
3.j-i=2,即j和i之间有一个字母,且s[i]=s[j],那么也是回文串,如ABA
代码:
class Solution {
public:
int countSubstrings(string s) {
int len = s.size(), res = 0;
vector<vector<bool>> dp(len, vector<bool>(len, false));
for (int i = len - 1; i >= 0; --i) {
for (int j = i; j < len; ++j) {
dp[i][j] = (s[i] == s[j]) && (j - i <= 2 || dp[i + 1][j - 1]);
if (dp[i][j]) ++res;
}
}
return res;
}
};
代码中
dp[i][j] = (s[i] == s[j]) && (j - i <= 2 || dp[i + 1][j - 1]);
可以写成
if(s[i] != s[j])
dp[i][j] = False;
else if(s[i]==s[j] && j-i<=2)
dp[i][j] = True;
else
dp[i][j] = dp[i+1][j-1];
下面看一下循环变量:
j-i<=2
的情况每个位置不需要依赖其他位置就可以决定自己的值
对于其他位置,由递推公式可以看出一个位置的值是由其左下角的值决定的
2.回文中心
将每个字母分别作为回文中心然后向两边扩展,分两种情况,一种是自己为中心,第二种自己和下一个一起为中心
class Solution {
public:
int countSubstrings(string s) {
int len = s.size(), res = 0;
for (int i = 0; i < len; ++i) {
int mid1 = i, mid2 = i;//奇数
while (mid1 >= 0 && mid2 < len && s[mid1] == s[mid2]) { //两边不能超过原字符串的边界
--mid1; ++mid2; ++res;
}
mid1 = i, mid2 = i+1;//偶数
while (mid1 >= 0 && mid2 < len && s[mid1] == s[mid2]) {
--mid1; ++mid2; ++res;
}
}
return res;
}
};
3,马拉车算法没看