647. 回文子串
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
输入:“abc”
输出:3
解释:三个回文子串: “a”, “b”, “c”
示例 2:
输入:“aaa”
输出:6
解释:6个回文子串: “a”, “a”, “a”, “aa”, “aa”, “aaa”
提示:
输入的字符串长度不会超过 1000 。
方法一
动态规划。dp[i][j]
表示[i, j)
区间内的字符串是否是回文串. 时间复杂度O(n^2)
,空间复杂度O(n^2)
.
代码
class Solution {
public int countSubstrings(String s) {
int n = s.length();
boolean[][] dp = new boolean[n+1][n+1];
for (int i=0; i<n; ++i) {
dp[i][i] = dp[i][i+1] = true;
}
int cnt = n;
for (int w=2; w<=n; ++w) {
for (int i=0; i<=n-w; ++i) {
if (s.charAt(i) == s.charAt(i+w-1)) {
dp[i][i+w] = dp[i+1][i+w-1];
if (dp[i][i+w]) {
++cnt;
}
}
}
}
return cnt;
}
}
方法二
遍历字符串的每个字符,以此为中心向两边扩展判断是否回文,分回文子串的长度是奇数还是偶数进行讨论。时间复杂度O(n^2)
,空间复杂度O(1)
.
代码
class Solution {
public:
int countSubstrings(string s) {
int n = s.size(), cntOdd = n, cntEven = 0;
for (int i=0; i<n; ++i) {
for (int j=1; j<=std::min(i, n-1-i); ++j) {
if (s[i-j] == s[i+j]) {
++cntOdd;
} else {
break;
}
}
for (int j=0; j<=std::min(i, n-2-i); ++j) {
if (s[i-j] == s[i+j+1]) {
++cntEven;
} else {
break;
}
}
}
return cntOdd + cntEven;
}
};