• manacher算法解析


    manacher是很简单的字符串回文算法,作用是O(n)求出一个字符串的最长回文子串

    下面给出这一算法的详解

    首先,我们设原字符串是aaabba,很显然,这个字符串最长的回文子串长度为4

    那么我们就要思考一种算法来计算出这个长度

    于是manacher横空出世

    首先,我们知道,一个回文子串一定有一个对称轴(或者你叫对称中心?),所以正常来讲,如果想O(n)求出最长回文子串,我们只需枚举每个对称轴,然后O(1)递推即可

    可是现在就产生了一个问题:如果原字符串是上面说的那样,那...对称轴是在ab中间的啊,这怎么找出来啊

    所以manacher需要一个操作,即在所有中间的位置插入一个'#'之类的无用字符,这样我们就可以忽略掉对称轴在两个字符中间的情况,只考虑对称轴落在字符上的情况即可

    所以我们记p[i]表示以i为回文中心,回文半径为p[i]

    然后我们考虑递推

    怎么推?

    我们记录一个maxp,表示在i之前所有的回文中心中,回文右端点最远在哪,记p0表示这个最远的右端点所对应的回文中心

     看蒙了?举个例子:

    (图中黑线表示字符串,p0为回文中心,maxp为回文右端点)

    接下来,我们考虑如何用这个东西维护p[i]

    这是需要分类讨论的,即:

    ①:

    若i<maxp,有:

    p[i]=min(p[2*p0-i],p[p0]+p0-i);

    这一点是显而易见的:如果i<maxp,那么我们显然可以找出一个j,使j与i关于p0对称,于是j=2*p0-i

    而根据对称性,j周围的字符一定和i周围的字符相同,所以p[i]可以由p[j]来更新

    如图所示,由于对称性,所以i右侧一部分和j左侧一部分相同,同时i左侧一部分和j右侧一部分相同,同时根据j的对称性,j左右两侧相同,故i左右两侧相同,为回文。

    至于另一个也很好理解,就是从i到maxp的一段,假设他整个都能构成回文。这一值和刚才对称求出的一个值取最小值才能保证结果的合理性。

    ②:i>=maxp

    没什么办法,暴力吧..

    接下来谈谈暴力:

    其实无论是情况①还是情况②都需要暴力,因为我们无法保证①求出的是最大值,我们只能保证①求出的是一个可能的合法答案

    所以我们需要暴力从p[i]的已有值开始向下跳,跳到不能跳为止即可

    剩下的就是代码了

    比较好些

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    using namespace std;
    char a[51000005];
    char s[102000005];
    int p[51000005];
    int maxp,p0,l;
    int ans=1;
    void manacher()
    {
    	for(int i=1;i<l;i++)
    	{
    		if(i<maxp)
    		{
    			int j=(p0<<1)-i;
    			p[i]=min(p[j],p[p0]+p0-i);
    		}else
    		{
    			p[i]=1;
    		}
    		while(s[i-p[i]]==s[i+p[i]])
    		{
    			p[i]++;
    		}
    		if(i+p[i]>maxp)
    		{
    			p0=i;
    			maxp=i+p[i];
    		}
    	}
    }
    int main()
    {
    	scanf("%s",a+1);
    	l=strlen(a+1);
    	p[1]=1;
    	s[0]=s[1]='#';
    	for(int i=1;i<=l;i++)
    	{
    		s[2*i]=a[i];
    		s[2*i+1]='#';
    	}
    	l=(l<<1)+2;
    	s[l]='0';
    	manacher();
    	for(int i=1;i<=l;i++)
    	{
    		ans=max(ans,p[i]-1);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
  • 相关阅读:
    Crystal Reports基础知识
    Dashboard与中国式报表的区别以及常见的Dashboard控件
    函数总结
    SQL Server 索引使用入门
    Linux+C 开发基础
    vi 开发环境~~转载
    linux mysql 基础操作使用
    sourceinsight 快捷键 转帖
    vi 利器
    fedora 7 英文环境 的汉字显示
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10764210.html
Copyright © 2020-2023  润新知