1. 动态规划
struct huiwen{
int start;
int end;
};
char * longestPalindrome(char * s){
long long int n;
n=strlen(s);
bool dp[n][n];
//dp[i][j]表示从第i个字符到第j个字符组成的字符串是否为回文子串
memset(dp, 0, sizeof(dp));
for(int i=0;i<n;i++){
dp[i][i]=true;
}
struct huiwen max; //记录最长回文字串的起始位置和终止位置
max.start=0;
max.end=0;
for(int L=2;L<=n;L++){ //枚举长度
for(int l=0;l<n;l++){ //枚举左边界
int r=L+l-1;
if(r>=n) break; //跳出一层循环
if(l+1 <= r-1) //回文子串长度最小为3
dp[l][r]= dp[l+1][r-1] && s[l]==s[r];
else //回文子串长度为2
dp[l][r]= s[l]==s[r];
if(dp[l][r]){ //如果是回文子串
if(L>(max.end-max.start+1)) { //如果这个回文子串更长,记录它的起始位置和终止位置
max.start=l;
max.end=r;
}
}
}
}
s[max.end+1]='\0';
//printf("max.start=%d max.end=%d\n",max.start,max.end);
return &s[max.start];
}
2.中心扩展算法
struct huiwen{
int start;
int end;
};
struct huiwen expandAroundCenter(char *s, int left, int right){
long long int n;
n=strlen(s);
while(left>=0 && right<n && s[left]==s[right]){
left--;
right++;
}
struct huiwen ans;
ans.start=left+1;
ans.end=right-1;
return ans;
}
char * longestPalindrome(char * s){
long long int n;
n=strlen(s);
struct huiwen max;
max.start=0;
max.end=0;
struct huiwen res;
for(int i=0;i<n;i++){
res=expandAroundCenter(s, i, i);
if((res.end-res.start)>(max.end-max.start))
max=res;
res=expandAroundCenter(s, i, i+1);
if((res.end-res.start)>(max.end-max.start))
max=res;
}
s[max.end+1]='\0';
return &s[max.start];
}
3.Manacher算法(马拉车算法)
struct huiwen{
int start;
int end;
};
int SolveArm(char *s, int left, int right){ //求臂长
long long int n;
n=strlen(s);
while(left>=0 && right<n && s[left]==s[right]){
left--;
right++;
}
return (right-left-2)/2; //[(right-1)-(left-1)]/2
}
//Manacher算法(马拉车算法)
//只针对长度为奇数的子串
struct huiwen Manacher(char *s){
long long int n;
n=strlen(s);
int arm_len[n];
struct huiwen ans;
ans.start=0;
ans.end=-1;
int j=-1, j_add_arm=-1; //j是已得的回文子串能覆盖的最大范围
for(int i=0;i<n;i++){
int i_arm;
if(j_add_arm>i){ //如果能覆盖到i
int i_sym = 2*j-i; //i关于j镜面对称的位置为:j-(i-j)
int min_arm = fmin( arm_len[i_sym], j_add_arm-i) +1 ;//最关键的一步!
i_arm = SolveArm(s, i-min_arm, i+min_arm);//就不用从i开始扩展
}
else{
i_arm = SolveArm(s, i, i);
}
arm_len[i]=i_arm;
if(i+i_arm > j_add_arm){ //更新已得最长回文zi串 能覆盖的最大范围
j=i;
j_add_arm=i+i_arm;
}
if(i_arm*2+1 >= ans.end-ans.start+1){ //更新最长回文子串开始和结束的位置
ans.start=i-i_arm;
ans.end=i+i_arm;
}
}
return ans;
}
char * longestPalindrome(char * s){
long long int n;
n=strlen(s);
//插入#,对字符串进行预处理
char s1[2*n+2];
for(int i=0;i<n;i++){
s1[2*i]='#';
s1[2*i+1]=s[i];
}
s1[2*n]='#';
s1[2*n+1]='\0';
//printf("%s\n",s1);
struct huiwen ans = Manacher(s1);
//得到最长回文字串开始和结束的位置(有#号)
//ans.start和ans.end处肯定对应的是#号
//s1中第i个位置对应s1中第(i-1)/2个位置,即[i/2]取整
int start=(ans.start+1)/2;
int end=(ans.end-1)/2;
s[end+1]='\0';
return &s[start];
}