您的位置:首页 > 其它

[hihocoder1032]最长回文子串

2016-11-30 22:21 323 查看
这里只是对于“最长回文子串”算法的简单定义与实现代码,具体请参照hihocoder的官网

问题描述

回文串的定义是正读与反读相同;子串的定义是任意连续字符串;求给定字符串的最长回文子串的长度。详情请参照hihocoder的官网,上面也有详细的算法介绍。

实现思路

1.
最简单的方法

从最长长度递减,检查所有的子串判断是否是回文子串,最差时间复杂度是O(n^2)。

2.
枚举字符串中心

以字符串中心的较短子串非回文,则较长子串必定非回文。

3.
利用之前的信息得到回文子串的最短长度

现在要求的是中心index=i的最长回文子串,如果index=j的最长回文子串长度maxPal[j]的右边界大于i(即maxPal[j]/2+j>i),那么可以知道对于任意2*i-maxPal[j]/2-j < k < maxPal[j]/2+j-i,有str[i+k] == str[2*j-i+k]。所以可以利用2*j-i处的最大回文子串的长度,得到当前处的回文子串长度的最小值。具体公式为maxPal[i]/2
>= min{j+maxPal[j]/2-i,maxPal[2*j-i]/2}。

此处不需要枚举所有的j以取得最大值,只需要计算j+maxPal[j]最大的j即可。

4.
奇偶串的处理

上诉方法只能处理长度为奇数的回文子串,通过拓展原串(即在字符前后都插入特殊字符),可以把算法拓展到偶数长度的回文子串。

这样得到的回文子串的长度需要去除特殊字符的部分。首先明确的是拓展后的字符串的最长回文子串首尾都是特殊字符,否则可以在两端加入特殊字符使得长度+2。这样就可以通过maxPal[i]/2的奇偶性反应i的奇偶性(/i对应的是否为特殊字符)。如果i对应的是特殊字符(即i为偶数,即maxPal[i]/2为偶数),则得到就是偶数的回文子串;反之依然。

代码如下

int maxPalindrome(char *str,int *maxPal,char *tmp_str){
int len = strlen(str);

//expand string
for (int i = 0;i < len;++i)
tmp_str[2*i+1] = str[i];

/**
max_j表示j+maxPal[j]/2最大的j;
result表示最长回文子串的长度(没有去特殊符号);
pal是暂时使用的变量,最后等于maxPal[i]/2+1;
tmp_start表示求得的当前位置的最短回文子串的长度;
**/
int max_j = 0,result = 1,pal,tmp_start;
len = len*2+1;
maxPal[0] = 1;
for (int i = 1;i < len;++i){
//求当前位置的最短回文子串长度
tmp_start = 0;
if (max_j+maxPal[max_j]/2-i > 0)
tmp_start = max_j+maxPal[max_j]/2-i;
if (2*max_j-i >= 0 && tmp_start > maxPal[2*max_j-i]/2)
tmp_start = maxPal[2*max_j-i]/2;

//从当前位置逐渐增加子串长度,判断是否回文,最后得到pal=maxPal[i]/2+1;
for (pal = tmp_start+1;i-pal > -1 && i+pal < len && tmp_str[i+pal] == tmp_str[i-pal];++pal);
maxPal[i] = pal*2-1;

if (maxPal[i] > result)
result = maxPal[i];
if (i+pal-1 > max_j+maxPal[max_j]/2)
max_j = i;
}

//result/2&1用于区分奇偶子串,第一部分求取除中心外的长度,第二部分用于判断中心是否为特殊符号,决定是否加1
return result/2/2*2+((result/2)&1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息