问题描述
给定一个字符串s,找出所有(i,j)使得s[i……j]为回文串。(回文串就是正看倒看都一样的串)
一、朴素算法
分该回文串是奇数串还是偶数串,遍历中心位向两边延伸
vector<int> d1(n), d2(n);
for (int i = 0; i < n; i++) {
d1[i] = 1;
while (0 <= i - d1[i] && i + d1[i] < n && s[i - d1[i]] == s[i + d1[i]]) {
d1[i]++;
}
d2[i] = 0;
while (0 <= i - d2[i] - 1 && i + d2[i] < n &&
s[i - d2[i] - 1] == s[i + d2[i]]) {
d2[i]++;
}
}
二、manacher算法
和z函数思想一样
,代码也基本一样,思想就是通过利用之前已求出来的值来计算当前值
分奇偶处理时
奇回文字符串
vector<int> d1(n);
for (int i = 0, l = 0, r = -1; i < n; i++) {
int k = (i > r) ? 1 : min(d1[l + r - i], r - i);
while (0 <= i - k && i + k < n && s[i - k] == s[i + k]) {
k++;
}
d1[i] = k--;
if (i + k > r) {
l = i - k;
r = i + k;
}
}
偶回文字符串 (假定和第i个相等的字符在i-1的位置)
vector<int> d2(n);
for (int i = 0, l = 0, r = -1; i < n; i++) {
int k = (i > r) ? 0 : min(d2[l + r - i + 1], r - i + 1);
while (0 <= i - k - 1 && i + k < n && s[i - k - 1] == s[i + k]) {
k++;
}
d2[i] = k--;
if (i + k > r) {
l = i - k - 1;
r = i + k;
}
}
优化算法
我们先做一个预处理,将原字符串每个间隙都用’#'隔开,这样的话,我们就不用分奇偶两种情况讨论了。比如
原串:a b a b a b c
先串:# a # b # a # b # a # b # c #
为什么不用分奇偶讨论了呢
设m是原串回文串的长度
当m时奇数时,比如是a b a,这时现回文字符串# a # b # a #的长度要比原回文字符串的长度大m+1(多了#的个数),所以现回文字符串的长度是2*m+1,是奇数。
当m时偶数时,比如是a b b a,这时现回文字符串# a # b # b a #的长度还是比原回文字符串的长度大m+1(多了#的个数),所以现回文字符串的长度是2*m+1,还是奇数。
总之,现回文字符串的长度会一直是奇数,可以直接按分奇偶处理时的奇数法处理
//预处理
stirng s,str;cin>>s;
int len=s.size();
for(int i=0;i<=2*len;++i)
{ if(i&1)str[i]=s[i/2];
else str[i]='#';
}