zoukankan      html  css  js  c++  java
  • O(n)回文子串(Manacher)算法

    O(n)回文子串(Manacher)算法

    资料来源网络 参见:http://www.felix021.com/blog/read.php?2040

    问题描述:

    输入一个字符串,求出其中最大的回文子串。子串的含义是:在原串中连续出现的字符串片段。回文的含义是:正着看和倒着看相同,如abba和yyxyy。

    解析:

    这里介绍O(n)回文子串(Manacher)算法

    算法基本要点:首 先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个特殊的符号。比如 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。 为了进一步减少编码的复杂度,可以在字符串的开始加入另一个特殊字符,这样就不用特殊处理越界问题,比如$#a#b#a#。

    下面以字符串12212321为例,经过上一步,变成了 S[] = "$#1#2#2#1#2#3#2#1#";

    然后用一个数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i]),比如S和P的对应关系:

    S     #  1  #  2  #  2  #  1  #  2  #  3  #  2  #  1  #
    P     1   2  1  2  5   2  1  4   1  2  1  6   1  2   1  2  1
    (p.s. 可以看出,P[i]-1正好是原字符串中回文串的总长度)

    下面计算P[i],该算法增加两个辅助变量id和mx,其中id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界。

    这个算法的关键点就在这里了:如果mx > i,那么P[i] >= MIN(P[2 * id - i], mx - i)。

    具体代码如下:

    复制代码
    if(mx > i)
    {
          p[i] = (p[2*id - i] < (mx - i) ? p[2*id - i] : (mx - i));
    }
    else
    {
           p[i] = 1;
    }
    复制代码

    当 mx - i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于 i 和 j 对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,所以必有 P[i] = P[j],见下图。

    当 P[j] > mx - i 的时候,以S[j]为中心的回文子串不完全包含于以S[id]为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以 S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx之后的部分是否对称,就只能一个一个匹配了。

    对于 mx <= i 的情况,无法对 P[i]做更多的假设,只能P[i] = 1,然后再去匹配了

    下面给出原文,进一步解释算法为线性的原因

    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #include <string.h>
    #include <stdio.h>
    #define maxn 110055
    using namespace std;
    char ma[maxn*2];
    int mp[maxn*2];
    int l;
    int  Manacher(char s[],int len)
    {
        int res = 0;
        l = 0;
        ma[l++] = '$';
        ma[l++] = '#';
        for(int i=0; i<len; i++)
        {
            ma[l++] = s[i];
            ma[l++] = '#';
        }
        ma[l] = 0;
        int mx = 0,id = 0;
        for(int i=0; i<l; i++)
        {
            mp[i] = mx >i ?min(mp[2*id-i],mx-i):1;
            while(ma[i+mp[i]] == ma[i-mp[i]]) mp[i] ++;
            if(i + mp[i] > mx)
            {
                mx = i + mp[i];
                id = i;
            }
        }
    }
    char s[maxn];
    int main()
    {
    //#ifndef ONLINE_JUDGE
    //          freopen("in.txt","r",stdin);
    //#endif // ONLINE_JUDGE
        while(~scanf("%s",s))
        {
            int  len = strlen(s);
            Manacher(s,len);
            int ans = 0;
            for(int i=0; i<l; i++)
            {
                ans = max(ans,mp[i] );
            }
            printf("%d
    ",ans-1);
        }
        return 0;
    }
  • 相关阅读:
    Asp.NET 4.0 ajax实例DataView 模板编程1
    ASP.NET 4.0 Ajax 实例DataView模板编程 DEMO 下载
    部分东北话、北京话
    .NET 培训课程解析(一)
    ASP.NET 4.0 Ajax 实例DataView模板编程2
    ASP.NET Web Game 架构设计1服务器基本结构
    ASP.NET Web Game 构架设计2数据库设计
    TFS2008 基本安装
    Linux上Oracle 11g安装步骤图解
    plsql developer远程连接oracle数据库
  • 原文地址:https://www.cnblogs.com/chenyang920/p/4451861.html
Copyright © 2011-2022 走看看