[hihocoder1032]最长回文子串

来源:互联网 发布:77pepecom现在域名 编辑:程序博客网 时间:2024/06/10 22:43

这里只是对于“最长回文子串”算法的简单定义与实现代码,具体请参照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);}



0 0
原创粉丝点击