原文地址:https://segmentfault.com/a/1190000003914228   http://blog.csdn.net/synapse7/article/details/18908413

灰常不错的学习资料

先预处理下:在每个字符的两边都插入一个特殊的符号,比如abba变成#a#b#b#a#,aba变成 #a#b#a#(因为Manacher算法只能处理奇数长度的字符串)。同时,为了避免数组越界,在字符串开头添加另一特殊符号,比如$#a#b#a#。

以字符串3212343219为例,处理后变成S[] = "$#3#2#1#2#3#4#3#2#1#9#"。
然后用一个数组Len[i]来记录以处理后的字符S[i]为中心的最长回文子串的半长度(包括S[i]):

 S   #  #  #  #  #  #  #  #  #  #  #
Len

最终的回文子串的长度即为maxLen-1)

Manacher算法的核心就在于减少Len[i]的计算量,使得原来O(n^2)的算法优化为O(n)。

下面两幅图的红框中的字符串为当前的右边界下标最大的回文子串,mid为其中心,right为其最右端+1,i'=2*mid-i为i关于mid的对称点。

现要计算Len[i],若以i'为中心的回文串(黄框)包含在最长回文子串中,则由回文串的对称性,以i为中心的回文串亦在最长回文子串中,即有Len[i]=Len[2*mid-i]

若以i'为中心的回文串(黄框)不包含在最长回文子串中,则以i为中心的回文串的半长度Len[i]=right-i+(之后继续判断的长度)

那么,为什么复杂度是O(n)的呢?

首先,主要影响复杂度的是s[i + len[i]] == s[i - len[i]]这一判断。

由下面的代码可知,当i<right时,我们就用常数的时间计算Len[i](此时不会执行while中的语句);当i>=right时,我们就继续判断:while (s[i + len[i]] == s[i - len[i]]) ++len[i]; 结束后,right < i + len[i]为真,更新right值。这样,我们至多进行n次s[i + len[i]] == s[i - len[i]]判断,故复杂度为O(n)。

完整代码:

 #include<bits/stdc++.h>
using namespace std;
const int mx = ; char ss[mx + ], s[(mx << ) + ]; /// ss为源串,s为处理后的字符串
int len[(mx << ) + ]; void debug()
{
int i;
for (i = ; s[i]; ++i) printf("%c ", s[i]);
puts("");
for (i = ; s[i]; ++i) printf("%d ", len[i]);
puts("");
} int main()
{
int right, mid, i, maxlen;
while (gets(ss))
{
memset(s, , sizeof(s));
s[] = '$';
for (i = ; ss[i]; ++i) s[(i << ) + ] = '#', s[(i << ) + ] = ss[i];
s[(i << ) + ] = '#';
memset(len, , sizeof(len));
maxlen = right = mid = ;
for (i = ; s[i]; ++i)
{
len[i] = (i < right ? min(len[(mid << ) - i], right - i) : );
/* 取min的原因:记点i关于mid的对称点为i',
若以i'为中心的回文串范围超过了以mid为中心的回文串的范围
(此时有i + len[(mid << 1) - i] >= right,注意len是包括中心的半长度)
则len[i]应取right - i(总不能超过边界吧) */
while (s[i + len[i]] == s[i - len[i]]) ++len[i];
maxlen = max(maxlen, len[i]);
if (right < i + len[i]) mid = i, right = i + len[i];
}
printf("%d\n", maxlen - );
debug();
}
return ;
}

补充:使用 Manacher 算法后我们得到了一个 len 数组,利用它我们可以在 O(1) 的时间内判断该字符串的任意子串是不是回文串,方法如下:

 inline bool Query(int l, int r) /// 判断源串中的某一子串 ss[l...r] 是否为回文串
{
return len[l + r + ] >= r - l + ;
}

0. 问题定义

最长回文子串问题:给定一个字符串,求它的最长回文子串长度。

如果一个字符串正着读和反着读是一样的,那它就是回文串。下面是一些回文串的实例:

12321 a aba abba aaaa tattarrattat(牛津英语词典中最长的回文单词)

1. Brute-force 解法

对于最长回文子串问题,最简单粗暴的办法是:找到字符串的所有子串,遍历每一个子串以验证它们是否为回文串。一个子串由子串的起点和终点确定,因此对于一个长度为n的字符串,共有n^2个子串。这些子串的平均长度大约是n/2,因此这个解法的时间复杂度是O(n^3)。

2. 改进的方法

显然所有的回文串都是对称的。长度为奇数回文串以最中间字符的位置为对称轴左右对称,而长度为偶数的回文串的对称轴在中间两个字符之间的空隙。可否利用这种对称性来提高算法效率呢?答案是肯定的。我们知道整个字符串中的所有字符,以及字符间的空隙,都可能是某个回文子串的对称轴位置。可以遍历这些位置,在每个位置上同时向左和向右扩展,直到左右两边的字符不同,或者达到边界。对于一个长度为n的字符串,这样的位置一共有n+n-1=2n-1个,在每个位置上平均大约要进行n/4次字符比较,于是此算法的时间复杂度是O(n^2)。

3. Manacher 算法

对于一个比较长的字符串,O(n^2)的时间复杂度是难以接受的。Can we do better?

先来看看解法2存在的缺陷。

1) 由于回文串长度的奇偶性造成了不同性质的对称轴位置,解法2要对两种情况分别处理;
2) 很多子串被重复多次访问,造成较差的时间效率。

缺陷2)可以通过这个直观的小

manacherO(n)求最长回文子串 hihocoder1032的更多相关文章

  1. hdu 3068 最长回文(manachar求最长回文子串)

    题目连接:hdu 3068 最长回文 解题思路:通过manachar算法求最长回文子串,如果用遍历的话绝对超时. #include <stdio.h> #include <strin ...

  2. PAT甲题题解-1040. Longest Symmetric String (25)-求最长回文子串

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6789177.html特别不喜欢那些随便转载别人的原创文章又不给 ...

  3. Manacher模板( 线性求最长回文子串 )

    模板 #include<stdio.h> #include<string.h> #include<algorithm> #include<map> us ...

  4. 求最长回文子串 - leetcode 5. Longest Palindromic Substring

    写在前面:忍不住吐槽几句今天上海的天气,次奥,鞋子里都能养鱼了...裤子也全湿了,衣服也全湿了,关键是这天气还打空调,只能瑟瑟发抖祈祷不要感冒了.... 前后切了一百零几道leetcode的题(sol ...

  5. 后缀数组 - 求最长回文子串 + 模板题 --- ural 1297

    1297. Palindrome Time Limit: 1.0 secondMemory Limit: 16 MB The “U.S. Robots” HQ has just received a ...

  6. Manacher算法 O(n) 求最长回文子串

    转自:http://bbs.dlut.edu.cn/bbstcon.php?board=Competition&gid=23474 其实原文说得是比较清楚的,只是英文的,我这里写一份中文的吧. ...

  7. Manacher算法——求最长回文子串

    首先,得先了解什么是回文串.回文串就是正反读起来就是一样的,如“abcdcba”.我们要是直接采用暴力方法来查找最长回文子串,时间复杂度为O(n^3),好一点的方法是枚举每一个字符,比较较它左右距离相 ...

  8. manacher算法求最长回文子串

    一:背景 给定一个字符串,求出其最长回文子串.例如: s="abcd",最长回文长度为 1: s="ababa",最长回文长度为 5: s="abcc ...

  9. 求最长回文子串,O(n)复杂度

    最长回文子串问题-Manacher算法 最长回文串问题是一个经典的算法题. 0. 问题定义 最长回文子串问题:给定一个字符串,求它的最长回文子串长度. 假设一个字符串正着读和反着读是一样的,那它就是回 ...

随机推荐

  1. 一个ibatis映射文件的例子(包含增删改单查,多查)

    <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-/ ...

  2. JDBC连接mysql时出现的ssl问题

    使用MySQL数据库时出现如下错误: WARN: Establishing SSL connection without server's identity verification is not r ...

  3. vue-cli全引入jquery

    欢迎加入前端交流群交流知识&&获取视频资料:749539640 vue-cli全引入jquery:(vue-cli使用webpack) 第一步: 在package.json文件里的de ...

  4. xBIM 实战04 在WinForm窗体中实现IFC模型的加载与浏览

    系列目录    [已更新最新开发文章,点击查看详细]  WPF底层使用 DirectX 进行图形渲染.DirectX  能理解可由显卡直接渲染的高层元素,如纹理和渐变,所以 DirectX 效率更高. ...

  5. JavaScript原型链:prototype与__proto__

    title: 'JavaScript原型链:prototype与__proto__' toc: false date: 2018-09-04 11:16:54 主要看了这一篇,讲解的很清晰,最主要的一 ...

  6. WordPress开启伪静态

    一.NGINX 的话在 domain.conf 的 server 增加代码: location / { try_files $uri $uri/ /index.php?$args; } 如果使用的是 ...

  7. perl脚本去除文件中重复数据

    今天第一天写博客,写的不好请大家多多指教,废话不多说了,干货送上: ############################################################# #!/u ...

  8. 常用的字符串方法 String ;

      字符串: 1,str.charAt(num);//根据下标查找字符串中对应的字符,返回对应下标的字符; 2,str.charCodeAt(num);//字符串中下标对应的那位字符的 Unicode ...

  9. css 遮照镂空效果

    实现这个效果有以下几种方式.(欢迎指出不足之处!!!)  一:最简单最粗暴的方法!截图! 实现原理:先截一张图片,然后写一个遮罩层,再把图片放上去就可以了! 过程过于简单,就别写代码跟截图效果了! 优 ...

  10. JVM内存管理简单剖析

    Java是一个跨平台语言,屏蔽操作系统的差异,无需关心复杂内存管理,做到编写一次到处运行.其强大的能力源于Java Virtual Machine (虚拟机)默默的付出.代码运行在虚拟机之上,虚拟机运 ...