647 Palindromic Substrings
求一个字符串的回文子串的个数,子串位置不同即算不同的回文子串。
eg: aaa有6个回文子串,a,a,a, aa, aa, aaa.
算法1:中心扩散法
计算从每一个中心位置向两边扩散得到的回文串个数,共有n+n-1个中心位置
code
class Solution {
public:
int countSubstrings(string s) {
int count = 0;
for (int center = 0; center < 2 * s.size() - 1; center++){
int left = center / 2, right = (center + 1) / 2;
while(left>=0&&right<s.size()&&s[left]==s[right]){
count++;
left--;
right++;
}
}
return count;
}
};
时间复杂度:O(n*n)
算法2 Manacher算法
该算法在一次遍历过程中,算出以每个字符串为中心的最长回文子串的半径长度。
详细解释见代码和注释。
code
class Solution{
public:
//计算所有的子回文字符串个数
int countSubstrings(string s){
if(s.size()==0) return 0;
//在首尾和每个字符间插入#,便于解决奇偶回文串的问题,第一个*是为了防止越界
string t = "*#";
for (int i = 0; i < s.size(); i++){
t += s[i];
t += "#";
}
//保存以每个字符为中心的最长回文串半径
vector<int> p(t.size(), 1);
//记录当前遍历到的回文串结束位置最靠后的回文串的中心和最右边位置,在每次i>=right时更新
int center = 1, right = 1, count = 0;
//从前向后遍历,更新P数组,同时计算count
for (int i = 2; i < t.size(); i++){
p[i] = i < right ? min(right - i + 1, p[2 * center - i]) : 1;
if(p[2*center-i]>=right-i+1){
center = i;
while (t[i - p[i]] == t[i + p[i]]){
p[i]++;
}
right = center + p[i] - 1;
}
count += p[i] / 2;
}
return count;
}
};
时间复杂度: O(n)