求最长回文子串问题—Manacher算法(O(n))
1.对原串进行转换
求回文串时奇偶串的算法会有差异,在这里做一个简单的处理,将奇回文串和偶回文串统一考虑,在每个字符间插入一个分隔符,串的首尾也要加,一般用“#”或“$”等。
原串:papapa
新串:#p#a#p#a#p#a#
这样一来,原来奇回文串还是奇数长度,偶数长度的回文串变成以“#”为中心的奇数回文串了。
2.len数组的性质
len[i]表示以字符T[i]为中心的最长回文半径
新串:# p # a # p # a # p # a #
len: 1 2 1 4 1 6 1 6 1 4 1 2 1
len数组有一个性质:len[i]-1为该回文串在原字符串中的位置
证明:
以T[i]为中心的最长回文字符串,其长度为:L=2*len[i]-1
以T[i]为中心的回文串一定是以“#”开头和结尾的,例如#p#a#p#,所以L减去最前面的#字符就是原串长度的二倍,即原串长为(L-1)/2,也即len[i]-1
3.len数组计算
从左往右依次计算Len[i],当计算Len[i]时,len[j]已经计算完毕(0<=j
// pata1040.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include"iostream"
#include"string"
#include"algorithm"
using namespace std;
const int N = 2005;
int main(){
string str;
getline(cin,str); //使用getline输入可以接收空格
int strlen = str.size();
//添加“#”字符生成新串
string strtmp = "#";
for (int i = 0; i < strlen; i++)
strtmp += str.substr(i, 1) + "#";
//mx为之前计算的最长回文串的右端点的最大值,id为取得这个最大值的位置的id
int id = 1, mx = 0;
int len[N];
for (int i = 0; i < strtmp.size(); i++){
if (mx>i)
len[i] = min(len[2 * id - i], mx - i);
else
len[i] = 1;
while (i >= len[i] && strtmp.substr(i + len[i], 1) == strtmp.substr(i - len[i], 1))
len[i]++;
if (i + len[i] > mx){
mx = i + len[i];
id = i;
}
}
int res = 1;
for (int i = 1; i < strtmp.size(); i++){
res = max(res, len[i]);
}
cout << res - 1 << endl;
return 0;
}
https://github.com/tewzh/pat/blob/master/.gitignore/a1040%20Longest%20Symmetric%20String