zoukankan      html  css  js  c++  java
  • 【知识点】Manacher算法详解

    Manacher算法

    算法简介

    (Manacher) 算法,即“马拉车”算法,是一种高效((O(n)))的求最长回文子串的算法。相比于 (KMP)(Manacher) 也许更好理解一些。

    算法原理

    对于传统的暴力解法,求最长回文子串的方式应该是对于每个位置 (i) ,向两边“扩大”以寻找回文子串,再记录答案。易证,此解法时间复杂度为 (O(n^2))

    众所周知,每一个毒瘤算法都有一个暴力的开头。

    (Manacher) 算法首先要对原字符串进行处理。因为回文串分为两种,“奇回文”和“偶回文”:

    1. "abcba"
    2. "abba"

    首先,在每两个字符之间放入一个没有出现在原串的字符,如 (mathtt{'#'}) ;接着,将字符串的两边插入另外两个不同的,且没有出现在原串的字符,如 (mathtt{'@'})(mathtt{'$'}) 。操作结果如下:

    1. "@a#b#b#a$"
    2. "@a#b#c#b#a$"

    神奇的事情发生了,“奇回文”和“偶回文”都转化成了“奇回文”。同时,在判定回文串的过程中也不用判边界了,因为修改后字符串边界字符不一样。

    除此之外, (Manacher) 算法还引入了一个数组 (p)(p_i) 表示以位置 (i) 为中心的“最长回文半径”。对于字符串 (mathtt{"@#a#b#b#a#d#c#a#c#d#a#$"}) 如表所示:

    (i) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
    (s_i) @ # a # b # b # a # d # c # a # c # d # a # $
    (p_i) 1 1 2 1 2 3 2 1 2 1 2 1 2 1 6 1 2 1 2 1 2 1 1

    显然,最终答案就是 (max{p_i-1}) 。那么 (Manacher) 算法就讲完了……等等, (p) 数组怎么求?

    算法过程

    推荐阅读~

    首先,看下图:

    引入两个变量, (mx)(id)(mx) 表示以 (id) 为中心点的最大回文子串右边界。

    假设现在要求 (p_i) ,那么就有:

    if(i<mx)
        p[i]=min(p[id*2-i],mx-i);
    

    这样就可以加快速度。但是……为什么?为什么为什么???

    (i'=id*2-i) ,也就是说,(i')(i) 关于 (id) 的对称点。因为是从前往后循环, (p_{i'})是已知的。下面开始分类讨论:

    • (p_{i'}>mx-i) ,可得以 (i') 为中心,以 (mx) 的对称点 (mx')(i') 的距离为半径形成的回文字符串是存在的,并且 (id)(mx')(id)(mx) 一一对应,所以 (mx)(i) 目前可以更新到的最大回文半径;
    • (p_{i'}<mx-i) ,也就是 (i') 的回文半径小于 (mx')(i') 的距离,可得 (p_i=p_{i'})

    于是就有了你看到的反人类代码。

    完整代码

    int manacher(string &s_src)
    {
        /*
         * @params s_src为源字符串,s为预处理后的字符串
         */
          string s="@";
        for(auto &ch: s_src)
        {
            s.push_back('#');
            s.push_back(ch);
        }
        s+="#$";
        int id,mx=0,res=0;
        for(int i=1;i<s.size()-1;i++)
        {
            if(i<=mx)
                p[i]=min(p[id*2-i],mx-i);
            while(s[i-p[i]]==s[i+p[i]])
                p[i]++;
            if(i+p[i]>mx)
                id=i,mx=i+p[i]-1;
            res=max(res,p[i]-1);
        }
        return res;
    }
    
  • 相关阅读:
    JAVA-初步认识-第三章-语句-switch
    JAVA-初步认识-第三章-if语句练习-星期和季节
    第三章-数据类型(3.3)
    JAVA-初步认识-第三章-局部代码块
    JAVA-初步认识-第三章-语句-if格式3
    JAVA-初步认识-第三章-语句-if格式1的演示
    JAVA-初步认识-第三章-语句-if格式2
    微信小程序图片使用示例
    推荐一款稳定快速免费的前端开源项目 CDN 加速服务
    基于mpvue的小程序项目搭建的步骤
  • 原文地址:https://www.cnblogs.com/ExplodingKonjac/p/13561740.html
Copyright © 2011-2022 走看看