C/C++教程

Manacher马拉车算法

本文主要是介绍Manacher马拉车算法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

  严格复杂度O(N)            

  step1:预处理,将奇偶变为奇数。

 对于一个串str长度为n,有n-1个空格,首位有两个,对这些空处理,长度变成2n+1。

可以加str中不存在的东西,比如#。

 

 

 

  step2: 构造数组p[n]

数组p[i]来记录字符串s[i]最长回文串向左向右扩张p[i]长度的最大值。

(全都是奇数)

 

 

(注意:必须构造成奇数序列才可以向两边扩充,得到p[i]数组,举个例子)

string :1221

p[i]     :1111

未发现回文

 

马士兵教育左神:https://www.bilibili.com/video/BV1YL4y1v7Hy?p=42

探寻时间复杂度

失败:

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

成功

 

把扩充和i变大绑在一起了

 

 

 

 

 

 

 

 

 

 

 

  

非左程云版马拉车

#include <vector>
#include <iostream>
#include <string>

using namespace std;

string Mannacher(string s){
    //插入"#"
    string t="$#";
    for(int i=0;i<s.size();++i)
    {
        t+=s[i];
        t+="#";
    }
    
    vector<int> p(t.size(),0);
    //mx表示某个回文串延伸在最右端半径的下标,id表示这个回文子串最中间位置下标
    //resLen表示对应在s中的最大子回文串的半径,resCenter表示最大子回文串的中间位置
    int mx=0,id=0,resLen=0,resCenter=0;

     //建立p数组
    for(int i=1;i<t.size();++i){
        p[i]=mx>i?min(p[2*id-i],mx-i):1;

        //遇到三种特殊的情况,需要利用中心扩展法
        while(t[i+p[i]]==t[i-p[i]])++p[i];

        //半径下标i+p[i]超过边界mx,需要更新
        if(mx<i+p[i]){
            mx=i+p[i];
            id=i;
        }

        //更新最大回文子串的信息,半径及中间位置
        if(resLen<p[i]){
            resLen=p[i];
            resCenter=i;
        }
    }

    //最长回文子串长度为半径-1,起始位置为中间位置减去半径再除以2
    return s.substr((resCenter-resLen)/2,resLen-1);
}

int main(){
    cout<<Mannacher("12212")<<endl;
    cout<<Mannacher("122122")<<endl;
    cout<<Mannacher("noon")<<endl;
    return 0;
}

 

https://windliang.wang/2019/06/24/%E4%B8%80%E6%96%87%E8%AE%A9%E4%BD%A0%E5%BD%BB%E5%BA%95%E6%98%8E%E7%99%BD%E9%A9%AC%E6%8B%89%E8%BD%A6%E7%AE%97%E6%B3%95/

https://www.cnblogs.com/transmigration-zhou/p/13471829.html

 

 

 

 

 

 

 

 

这篇关于Manacher马拉车算法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!