今天我想介绍一下如何求最大回文子串长度,感觉思想还是挺好的
给你一个字符串,让你找出其中的一个最长回文子串。
先说一下如何判断一个字符串是不是回文子串吧,这个可以通过哈希直接判断,就是预处理出来两个哈希数组,一个正着来,一个反着来,然后直接比较两个字符串的哈希值是否相同就好了,哈希数组一般直接开成无符号长整形,让他自动溢出,进制数一般选择131或者13331,下面附上代码:
//预处理哈希数组
int len=strlen(s+1);
p[0]=1;//记录p进制下的次方
for(int i=1;i<=len;i++)
{
ha1[i]=ha1[i-1]*131+s[i];//正着来
p[i]=p[i-1]*131;
}
for(int i=len;i>=1;i--)
ha2[i]=ha2[i+1]*131+s[i];//反着来
//判断以l为起点r为终点的字符串是否是回文串
bool check(int l,int r)
{
if(ha1[r]-ha1[l-1]*p[r-l+1]==ha2[l]-ha2[r+1]*p[r-l+1]) return true;
else
return false;
}
现在我们来看下如何找最大回文串:
我们必须要注意的一点是回文串的一些子串也是回文串,前提是关于回文串中心对称的子串,因此我们不难发现回文串的长度具有单调性,可以用二分来解决。
我们枚举回文串的中点,然后二分他的长度来找最大回文串,但是需要注意的是只有长度为奇数的回文串才会只有一个中点,所以我们求最大回文串时要分奇数和偶数讨论一下,最后取一个最大值就好了。
细节我在代码里面都已标明,下面直接上代码:
int len1=0,len2=0;//len1记录奇数回文串的最大长度,len2记录偶数回文串的最大长度
//二分求奇数回文串的最大长度
for(int i=1;i<=len;i++)
{
//二分回文子串长度的一半
int l=0,r=min(i-1,len-i);
while(l<r)
{
int mid=l+r+1>>1;
if(check(i-mid,i+mid))l=mid;
else r=mid-1;
}
len1=max(len1,1+2*l);
}
//二分求偶数回文串的最大长度
for(int i=1;i<=len;i++)
{
int l=0,r=min(i,len-i);
while(l<r)
{
int mid=l+r+1>>1;
if(check(i-mid+1,i+mid)) l=mid;
else r=mid-1;
}
len2=max(len2,l*2);
}
//最后对奇数回文串长度最大值和偶数回文串长度最大值取一个最大值即可
printf("%d\n",max(len1,len2));
这就是求一个字符串中最大回文子串的方法了,如果大家有更好的方法,欢迎在评论区里面讨论!