manacher 求最长回文子串

      昨天看到一个非常屌的求最长回文子串的O(n)算法。

      算法的过程是这样的:先对字符串进行预处理,相邻的字符串之间加上一个特殊的标记符号(这个符号在原串中是没有出现的),为了方便可以在开头加另外一个特殊的标记符号这样经过扩展的字符串就变成了从一开始的了。

      用一个数组P标记以当前字符为中心的最长回文子串可以向右延伸多少位,当不能延伸时P [ i ] = 1。然后,可以发现,不管回文串长度是奇数还是偶数,以第 i 个字符为中心的回文串的长度是 P [ i ] - 1 。这样算出了P数组之后扫描一遍即可得到最长回文子序列的长度。

      关键是如何求P数组。每次求得 id 位置的P[id]之后,更新一下当前能扫到的最远位置 max ;对于后面的字符,如果max超过了当前的下标,也就是之前这个位置已经被访问过,也就是当前位置的字符是在以id为中心的最长回文子串里面的。用和i关于id对称的一个点j(j=2*id-i)的P[j]值来更新。因为i和j是关于id对称的,又i包含在id的最长回文子串里面,所以可用p[2*id-i]来更新p[i]的值。又比如这种情况,0 0 0 0 0 j 0 0 0 id 0 0 0 i 0 max。用P[j]来更新P[i]的时候,明显有一个问题,j向右延伸的距离可能超过了max-i,而超出来的这部分在id那个回文子串里面是没有被访问过的,所以得取P  [ 2 * id - i ] 和 max - i 的最小值,即为P [ i ];

程序实现如下:

char s[maxn];
char str[maxn];
int p[maxn];
int sol() {
    int mx=0;
    int id;
    int n=strlen(s);

    str[0]='&';
    str[1]='#';
    for(int i=0; i<n; i++)
        str[i*2+2]=s[i],str[i*2+3]='#';

    n=n*2+2;
    for(int i=1; i<n; i++) {
        if(mx>i)p[i]=min(p[2*id-i],mx-i);
        else p[i]=1;
        while(str[i+p[i]]==str[i-p[i]])p[i]++;
        if(p[i]+i>mx)mx=p[i]+i,id=i;
    }
    int ans=0;
    for(int i=1; i<n; i++)
        ans=max(ans,p[i]-1);

    return ans;
}


int main() {
    while(scanf("%s",s)==1) {
        cout<<sol()<<endl;
    }
    return 0;
}

另外,上交的那本《算法与实现》当中也有这个算法,只不过没搞明白。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值