zoukankan      html  css  js  c++  java
  • Manacher算法(马拉车)求最长回文子串

    Manacher算法求最长回文字串

    算法思路

    按照惯例((・◇・)?),这里只是对算法的一些大体思路做一个描述,因为找到了相当好理解的博客可以参考(算法细节见参考文章)。

    一般而言,我们的判断回文算法的思想是从一个点开始向两边拓展直到无法拓展为止,这个时候就得到了回文串的长度,但这个算法的时间复杂度是(O(n^2))的。在这个算法进行的过程中,我们有可能会不断地拓展了重复的位置而产生重复计算,升高了时间复杂度。马拉车算法通过充分利用已经遍历过的信息,尽量不会重复去遍历已知信息的区段,而且利用一定的空间来记录信息,是一种空间换时间的做法。所谓利用信息,实际上是利用回文串本身的性质,具体的,是一个回文串包含回文字串时的关于对称轴对称的性质。分情况进行了不同处理。

    同时,为了避免代码的重复冗余,在原回文串中加入了'#','$'等字符,使奇偶统一讨论,而且能够较为方便的找回对应于原串的信息。

    代码

    #include <iostream>
    #include <cstring>
    #define max_n 1005
    using namespace std;
    int p[max_n];//p[i]表示以i为中心的最长回文的半径
    char s[max_n];//记录原串
    char t[max_n];//经处理的串
    int center = -1;//记录最长回文子串在原串中的起始位置
    int max_len = -1;//记录最长回文字串的长度
    int Init()//处理原串
    {
        int len = strlen(s);
        t[0] = '$';
        t[1] = '#';
        int j = 2;
        for(int i = 0;i<len;i++)
        {
            t[j++] = s[i];
            t[j++] = '#';
        }
        t[j] = '';
        return j;
    }
    int manacher()
    {
        int len = Init();
    
        int id;//当前回文子串中心
        int mx = 0;//当前回文子串右端点(不包含)
        for(int i = 0;i<len;i++)
        {
            if(i<mx)
            {
                p[i] = min(p[2*id-i],mx-i);//包含了两种情况
            }
            else
            {
                p[i] = 1;//一种情况
            }
            while(t[i+p[i]]==t[i-p[i]])
            {
                p[i]++;//看是否还可拓展
            }
            if(mx<i+p[i])//更新回文子串中心和右端
            {
                id = i;
                mx = i+p[i];
            }
            if(max_len<p[i]-1)
            {
                max_len = p[i]-1;//更新最长回文子串长度
                center = (i-p[i])/2;//及起始点
            }
        }
        return max_len;
    }
    int main()
    {
        cin >> s;
        cout << manacher() << endl;
        for(int i = center;i<max_len;i++)
        {
            cout << s[i];
        }
        cout << endl;
        return 0;
    }
    

    实例

    这里给一个实例:

    abbaho

    转化后为:$#a#b#b#a#h#o#,可尝试照着代码分析一下,看看mx和id是怎么变化的,对应情况又是怎么处理的

    处理串和原串的对应关系

    这里说一下处理后的串的信息怎么和原来的串对应上。

    这里就要举栗子啦。

    原串是abbaho,处理后$#a#b#b#a#h#o#,看中间的#的位置5,p[5]=5,此时原串的回文长度是4,发现4=p[5]-1;起始位置是0,发现(5-p[5])/2=0

    再来看看anppnb,处理后为$#a#n#p#p#n#b#,中间#的位置是7,p[7]=5,此时原串回文长度是4,发现4=p[7]-1;起始位置是1,发现(7-p[7])/2=1

    于是不完全归纳出:

    原串回文长度=p[处理串的回文中心位置]-1

    原串回文起始位置=(处理串回文中心位置-p[处理串回文中心位置])/2

    参考文章

    原串处理串对应关系请见:

    Grandyang,Manacher's Algorithm 马拉车算法,https://www.cnblogs.com/grandyang/p/4475985.html

    算法流程讲解请见:

    BIT祝威 ,[译+改]最长回文子串(Longest Palindromic Substring) Part II,https://www.cnblogs.com/bitzhuwei/p/Longest-Palindromic-Substring-Part-II.html

    具体的算法分析请见:

    刘毅,Manacher 算法 ,https://subetter.com/algorithm/manacher-algorithm.html

  • 相关阅读:
    SQL SERVER 运维日记-数据库备份
    SQL调优日记--并行等待的原理和问题排查
    数据库服务器构建和部署最佳实践
    实战案例--TEMPDB暴涨
    关于TRIM的优化技巧
    SQL SERVER 的前世今生--各版本功能对比
    Sleeping会话导致阻塞原理(下)
    SQL SERVER运维日记--收缩数据库
    SQLSERVER 运维日记-数据库状态
    EXPERT FOR SQL SERVER诊断系列--索引
  • 原文地址:https://www.cnblogs.com/zhanhonhao/p/11338549.html
Copyright © 2011-2022 走看看