这个马拉车算法Manacher‘s Algorithm是用来查找一个字符串的最长回文子串的线性方法,由一个叫Manacher的人在1975年发明的,这个方法的最大贡献是在于将时间复杂度提升到了线性,这是非常了不起的。对于回文串想必大家都不陌生,就是正读反读都一样的字符串,比如 "bob", "level", "noon" 等等,那么如何在一个字符串中找出最长回文子串呢,可以以每一个字符为中心,向两边寻找回文子串,在遍历完整个数组后,就可以找到最长的回文子串。但是这个方法的时间复杂度为O(n*n),并不是很高效,下面我们来看时间复杂度为O(n)的马拉车算法。

由于回文串的长度可奇可偶,比如"bob"是奇数形式的回文,"noon"就是偶数形式的回文,马拉车算法的第一步是预处理,做法是在每一个字符的左右都加上一个特殊字符,比如加上'#',那么

bob    -->    #b#o#b#

noon    -->    #n#o#o#n#

这样做的好处是不论原字符串是奇数还是偶数个,处理之后得到的字符串的个数都是奇数个,这样就不用分情况讨论了,而可以一起搞定。接下来我们还需要和处理后的字符串t等长的数组p,其中p[i]表示以t[i]字符为中心的回文子串的半径,若p[i] = 1,则该回文子串就是t[i]本身,那么我们来看一个简单的例子:

# 1 # 2 # 2 # 1 # 2 # 2 #
1 2 1 2 5 2 1 6 1 2 3 2 1

由于第一个和最后一个字符都是#号,且也需要搜索回文,为了防止越界,我们还需要在首尾再加上非#号字符,实际操作时我们只需给开头加上个非#号字符,结尾不用加的原因是字符串的结尾标识为'\0',等于默认加过了。通过p数组我们就可以找到其最大值和其位置,就能确定最长回文子串了,那么下面我们就来看如何求p数组,需要新增两个辅助变量mx和id,其中id为最大回文子串中心的位置,mx表示其半径,这个算法的最核心的一行如下:

p[i] = mx > i ? min(p[ * id - i], mx - i) : ;

可以这么说,这行要是理解了,那么马拉车算法基本上就没啥问题了,那么这一行代码拆开来看就是

如果mx > i, 则 p[i] = min(p[2 * id - i], mx - i)

否则, 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 <vector>
#include <iostream>
#include <string>

using namespace std;

string Manacher(string s) {
    // Insert '#'
    string t = "$#";
    ; i < s.size(); ++i) {
        t += s[i];
        t += "#";
    }
    // Process t
    vector<);
    , id = , resLen = , resCenter = ;
    ; i < t.size(); ++i) {
        p[i] = mx > i ? min(p[ * id - i], mx - i) : ;
        while (t[i + p[i]] == t[i - p[i]]) ++p[i];
        if (mx < i + p[i]) {
            mx = i + p[i];
            id = i;
        }
        if (resLen < p[i]) {
            resLen = p[i];
            resCenter = i;
        }
    }
    , resLen - );
}

int main() {
    ";
    cout << Manacher(s1) << endl;
    ";
    cout << Manacher(s2) << endl;
    string s = "waabwswfd";
    cout << Manacher(s) << endl;
}

Manacher's Algorithm 马拉车算法的更多相关文章

  1. Manacher&#39;s Algorithm 马拉车算法(求最长回文串)

    作用:求一个字符串中的最长子串,同时还可以求所有子串的长度. 题目链接: https://vjudge.net/contest/254692#problem/B 最长回文串长度的代码: int Man ...

  2. Manacher's Algorithm 马拉车算法

    作用:求一个字符串中的最长子串,同时还可以求所有子串的长度. 题目链接: https://vjudge.net/contest/254692#problem/B 代码: #include<bit ...

  3. Manacher’s Algorithm (神啊)

    (转载自)http://blog.csdn.net/hopeztm/article/details/7932245 这里描述了一个叫Manacher’s Algorithm的算法. 算法首先将输入字符 ...

  4. Manacher&#39;s Algorithm(马拉车算法)

    ## 背景 该算法用于求字符串的最长回文子串长度. ## 参考文章 >[最长回文子串——Manacher 算法](https://segmentfault.com/a/1190000003914 ...

  5. 什么是马拉车算法(Manacher&#39;s Algorithm)?

    提出问题 最长回文子串问题:给定一个字符串,求它的最长回文子串长度. 如果一个字符串正着读和反着读是一样的,那它就是回文串.如a.aa.aba.abba等. 暴力解法 简单粗暴:找到字符串的所有子串, ...

  6. 小白月赛13 B小A的回文串 (马拉车算法求最长回文子串)

    链接:https://ac.nowcoder.com/acm/contest/549/B来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...

  7. BZOJ 2342: [Shoi2011]双倍回文 马拉车算法/并查集

    2342: [Shoi2011]双倍回文 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1123  Solved: 408 题目连接 http://w ...

  8. 2015 UESTC 搜索专题M题 Palindromic String 马拉车算法

    Palindromic String Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/contest/s ...

  9. Manacher&#39;s algorithm

    Manacher's algorithm 以\(O(n)\)的线性时间求一个字符串的最大回文子串. 1. 预处理 一个最棘手的问题是需要考虑最长回文子串的长度为奇数和偶数的情况.我们通过在任意两个字符 ...

随机推荐

  1. CentOS7 运行级别

    linux运行的级别7个级别运行级别的查看使用 runlevelrunlevelN 3 //运行在3级别,可以理解成命令行级别级别之间的切换需要使用init x 0 //关机3 //多用户的命令行级别 ...

  2. Android网络访问库 - Retrofit学习(1)基础

    Retrofit是什么 Retrofit是一个类型安全的HTTP客户端,支持Android和Java.它是Square公司开源的项目,当前版本2.0. 在实际开发中,我们Retrofit配合OKHTT ...

  3. ural 1268. Little Chu

    1268. Little Chu Time limit: 0.25 secondMemory limit: 64 MB The favorite occupation of Little Chu is ...

  4. sqlserver 视图能否有变量

    不能,sqlserver 视图一般不能有变量,也不能带存储过程

  5. Object-C : Block的实现方式

    摘自:http://www.cnblogs.com/GarveyCalvin/p/4204167.html> Date : 2015-12-4 前言:我们可以把Block当作一个闭包函数,它可以 ...

  6. UVa 10420 List of Conquests

    题意就是有N个pl妹子,然后每行第一个单词是妹子的国籍,后面是妹子的名字. 你的任务就是统计相同国籍妹子的个数,然后按字母表顺序输出. 我首先把所有的国籍都读入,然后用qsort()按字母表顺序排序. ...

  7. VS2010界面主题更换全过程

    VisualStudio 2010的界面默认是蓝色的,背景是白色,字体是宋体,这些设置习惯了还好,但是可能看多了不怎么舒服.而且如果以前是用VS 6.0的知道,它使用的字体更为舒服清晰.所以,可以对V ...

  8. 读《编写高质量代码:改善JavaScript程序的188个建议》1

    建议3:减少全局变量污染 定义全局变量有3种方式: ❑在任何函数外面直接执行var语句. var f='value'; ❑直接添加一个属性到全局对象上.全局对象是所有全局变量的容器.在Web浏览器中, ...

  9. html进阶css(1)

    <!doctype html> <html> <head> <meta http-equiv="content-type" content ...

  10. Angular-UI-Router 学习笔记

    路由 Route 我在 慕课网 学习 AngularJS 为什么用 Route AJAX 请求不会留下 History 记录 用户无法直接通过 URL 进入应用中的指定页面(保存书签.链接分享给朋友) ...