输入一个字符串Str,输出Str里最长回文子串的长度。
回文串:指aba、abba、cccbccc、aaaa这种左右对称的字符串。
串的子串:一个串的子串指此(字符)串中连续的一部分字符构成的子(字符)串
例如 abc 这个串的子串:空串、a、b、c、ab、bc、abc
Input
输入Str(Str的长度 <= 1000)
Output
输出最长回文子串的长度L。
Sample Input
daabaac
Sample Output
5
直接暴力也可以写 不过学会算法能够解决所有这类题型
这道题用马拉车写
先上2个大佬博客 [大佬1]大佬2(https://blog.csdn.net/mashizuren/article/details/107868921)
1.修改字符串 使之长度变成奇数
对于样例,daabaac->@#d#a#a#b#a#a#c#
2.其实个人感觉理解了中心代码 就相当于理解了这个算法的80%,就是求当前位置的回文半径p[i]时,如果i<mx(当前最大回文串的右边界)利用关于以id(当前最大回文串的中心)与i对称的点j可以求得 如果p[j]<mx-i 那么p[i]=p[j];
如果p[j]>mx-i,这时就越界了,而我们只知道[mx`,mx]这段范围是回文串,所以越界的字符半径只能一个一个求得 ,此时p[i]=mx-i 。
在这里插入代码片//最大回文串长度 等于更改后的最大回文半径-1
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
int p[1010]; //当前位置的半径
int id=0 ,rmax=0 ,maxx; //半径中心 mx为以id为中心的最右边的边界
char str1[1010],str2[1010];
void manache()
{
int l=strlen(str1),k=2;
str2[0]='@';
str2[1]='#';
for(int i=0;i<l;i++)
{
str2[k++]=str1[i];
str2[k++]='#';
}
// k--;
// str2[k]='#';
/*for(int i=0;i<k;i++)
printf("%c",str2[i]);
printf("$$$$$$$$\n");
int s=strlen(str2);
for(int i=0;i<s;i++)
printf("%c",str2[i]);
printf("@@@@\n");
printf("####%d\n",k);
printf("$$$$%d\n",s);*/
maxx=0;
for(int i=0;i<k;i++)
{
// int id=0,rmax=0;
if(i<rmax)
p[i]=min(p[2*id-i],rmax-i);
else
p[i]=1;
while(str2[p[i]+i]==str2[i-p[i]])
p[i]++;
if(p[i]+i>rmax)
{
rmax=p[i]+i;
id=i;
}
maxx=max(maxx,p[i]-1); //找最大回文半径
// printf("#####%d\n",p[id]);
}
printf("%d",maxx);
}
int main()
{
gets(str1);
//memset(p,0,sizeof(p));
// youhua();
manache();
// printf("%d\n",maxx);
return 0;
}