lintcode最长回文子串(Manacher算法)
题目来自lintcode, 链接:http://www.lintcode.com/zh-cn/problem/longest-palindromic-substring/
最长回文子串
给出一个字符串(假设长度最长为1000),求出它的最长回文子串,你可以假定只有一个满足条件的最长回文串。
样例
给出字符串 "abcdzdcab",它的最长回文子串为 "cdzdc"。
挑战
O(n2) 时间复杂度的算法是可以接受的,如果你能用 O(n) 的算法那自然更好。
一. 首先给出O(n^2)的算法
思路:dp[i][k]表示第i个位置开始长度为k的串的最大回文串的长度, j=i+k-1
当 s[i] == s[j] && dp[i+1][k-2] == k-2, dp[i][k] = dp[i+1][k-2] + 2;
否则 dp[i][k] = max(dp[i+1][k-1], dp[i][k-1]);
并记录dp[i][k]的最大值,最后找到最长回文子串的区间。
int dp[][];
string longestPalindrome(string& s) {
// Write your code here
O(n^)
int len = s.size();
memset(dp, , sizeof(dp));
for(int i=; i<len; ++i)
dp[i][] = ;
int ld=, rd=, maxL = ;
for(int k=; k<=len; ++k){
for(int i=, j; i<len && (j=i+k-)<len; ++i){
if(s[i] == s[j] && dp[i+][k-] == k-)
dp[i][k] = dp[i+][k-] + ;
else
dp[i][k] = max(dp[i+][k-], dp[i][k-]);
if(maxL<dp[i][k]){
maxL = dp[i][k];
ld = i;
rd = j;
}
}
}
return s.substr(ld, rd-ld+);
}
二.然后看一下复杂度为O(n)的Manacher算法
2.1 先说一下这个算法的思想:
用一个数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i])。
2.2 算法基本要点:
这个算法不能求出最长回文串长度为偶数回文串。用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在相邻两个字符之间插入一个特殊的符号。比如 abba 变成 a#b#b#a。 为了进一步减少编码的复杂度,可以在字符串的开始加入另一个特殊字符,这样就不用特殊处理越界问题,比如$a#b#b#a。
2.3 具体说一个例子:
S[] 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1
P[] 1 1 2 1 2 1 4 1 2 1 5 1 2 1 1
(p.s. 可以看出,P[i]-1正好是原字符串中回文串的总长度)
2.4 为啥要对字符串进行处理(插入'#')
如果不对字符进行处理, 对于最长回文串为偶数的情况下:
S[] 1 2 1 1 2 1
P[] 1 2 1 1 2 1
对字符进行处理,对于最长回文串为偶数的情况下:
S[] 1 # 2 # 1 # 1 # 2 # 1
P[] 1 1 3 1 2 6 2 1 3 1 1
可见不对字符进行处理,对于最长回文串为偶数的情况是不能得到最大的回文串的长度。
2.5 如何计算P数组的值:
算法增加两个辅助变量id和mx,其中id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界。
当 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,然后再去匹配了。
2.6 寻找最大长度的回文子串:
看一种情况:
S[] 1 # 2 # 2
P[] 1 1 2 2 1
首先, P中的最大值为2,但是最大值有两个,我们应该选择哪一个?其实,如果P中的最大值对应的字符不是'#',显然不能得到最大长度的回文串。所以当我们遇到这种情况时(maxP == P[i] && S[i]=='#')要更新最大值所在位置。
2.7 最后代码:
class Solution {
public:
/**
* @param s input string
* @return the longest palindromic substring
*/
string manacher(string& str){
int *p = new int[str.size()]();
memset(p, , sizeof(p));
int mx = , id = ;
for(int i=; i<str.size(); i++){
if(mx > i)
p[i] = min(p[*id-i], mx-i);
else
p[i] = ;
while(str[i - p[i]] == str[i + p[i]])
++p[i];
if(i + p[i] > mx){
mx = i + p[i];
id = i;
}
}
//寻找数组P中的最大值的位置
int maxP = ;
for(int i=; i<str.size(); ++i)
if(maxP < p[i] || (maxP == p[i] && str[i]=='#')){
maxP = p[i];
id = i;
}
//根据id,确定最长回文串的区间
int ld = id-p[id]+, rd = id+p[id]-;
string ans = "";
for(int i=ld; i<=rd; ++i)
if(str[i]!='#')
ans += str[i];
return ans;
}
string longestPalindrome(string& s) {
// Write your code here
//采用manacher算法,O(n)的时间复杂度
int len = s.size();
//首先预处理字符串,每两个字符之间插入'#'
int k = -;
for(int i=; i<len; ++i)
s.insert(k+=, , '#');
s.insert(, , '$');
return manacher(s);
}
};
lintcode最长回文子串(Manacher算法)的更多相关文章
- 九度OJ 1528 最长回文子串 -- Manacher算法
题目地址:http://ac.jobdu.com/problem.php?pid=1528 题目描述: 回文串就是一个正读和反读都一样的字符串,比如"level"或者"n ...
- 最长回文子串—Manacher 算法 及 python实现
最长回文子串问题:给定一个字符串,求它的最长回文子串长度.如果一个字符串正着读和反着读是一样的,那它就是回文串. 给定一个字符串,求它最长的回文子串长度,例如输入字符串'35534321',它的最 ...
- hihocoder #1032 : 最长回文子串 Manacher算法
题目链接: https://hihocoder.com/problemset/problem/1032?sid=868170 最长回文子串 时间限制:1000ms内存限制:64MB 问题描述 小Hi和 ...
- 5. Longest Palindromic Substring(最长回文子串 manacher 算法/ DP动态规划)
Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...
- HiHo 1032 最长回文子串 (Manacher算法求解)
/** * 求解最长回文字串,Manacher算法o(n)求解最长回文子串问题 **/ #include<cstdio> #include<cstdlib> #include& ...
- hihoCoder #1032 : 最长回文子串 [ Manacher算法--O(n)回文子串算法 ]
传送门 #1032 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相 ...
- 51nod1089 最长回文子串 manacher算法
0. 问题定义 最长回文子串问题:给定一个字符串,求它的最长回文子串长度. 如果一个字符串正着读和反着读是一样的,那它就是回文串.下面是一些回文串的实例: 12321 a aba abba aaaa ...
- 最长回文子串Manacher算法模板
Manacher算法能够在O(N)的时间复杂度内得到一个字符串以任意位置为中心的回文子串.其算法的基本原理就是利用已知回文串的左半部分来推导右半部分. 首先,在字符串s中,用rad[i]表示第i个字符 ...
- 求最长回文子串——Manacher算法
回文串包括奇数长的和偶数长的,一般求的时候都要分情况讨论,这个算法做了个简单的处理把奇偶情况统一了.算法的基本思路是这样的,把原串每个字符中间用一个串中没出现过的字符分隔开来(统一奇偶),用一个数组p ...
随机推荐
- 使用poco 的NetSSL_OpenSSL 搭建https 服务端,使用C++客户端,java 客户端访问,python访问(python还没找到带证书访问的代码.)
V20161028 由于项目原因,需要用到https去做一些事情. 这儿做了一些相应的研究. 这个https 用起来也是折腾人,还是研究了一周多+之前的一些积累. 目录 1,java client 通 ...
- linux进程后台运行及输出重定向
本机环境为ubuntu 14.04 以ping www.baidu.com为例: 1.程序的前台运行 ping www.baidu.com 可以看到,屏幕上输出了baidu返回的结果 2.实现程序后台 ...
- WebP 原理和 Android 支持现状介绍(转)
本文为腾讯Bugly开发者社区 投稿,作者:soonlai,版权归原作者所有,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/582939577ef9c5b70855 ...
- 打造AngularJs2.0开发环境
angularjs2.0刚发布, typescript2.0也刚发布, 于2016.9.29记录. 参考文档:https://angular.cn/docs/ts/latest/quickstart. ...
- 字典NSDictionary以及NSMutableDictionary的用法总结
做过Java语言 或者 C语言 开发的朋友应该很清楚 关键字map 吧,它可以将数据以键值对儿的形式储存起来,取值的时候通过KEY就可以直接拿到对应的值,非常方便.在Objective-C语言中 词典 ...
- PYTHON黑帽编程1.5 使用WIRESHARK练习网络协议分析
Python黑帽编程1.5 使用Wireshark练习网络协议分析 1.5.0.1 本系列教程说明 本系列教程,采用的大纲母本为<Understanding Network Hacks At ...
- 写一个脚本,自动启动tomcat
我的服务器是使用tomcat的,时不时tomcat的进程会突然结束掉,不知道为什么,从日志上看也没有任何可疑之处,貌似就这样突然没了,接下来的日志都是重新启动tomcat之后打印的了.原因找不到,但要 ...
- 多线程中的锁系统(二)-volatile、Interlocked、ReaderWriterLockSlim
上章主要讲排他锁的直接使用方式.但实际当中全部都用锁又太浪费了,或者排他锁粒度太大了,本篇主要介绍下升级锁和原子操作. 阅读目录 volatile Interlocked ReaderWriterLo ...
- MySQL 存储过程和函数
概述 一提到存储过程可能就会引出另一个话题就是存储过程的优缺点,这里也不做讨论,一般别人问我我就这样回答你觉得它好你就用它.因为mysql中存储过程和函数的语法非常接近所以就放在一起,主要区别就是函数 ...
- TCP状态
TCP状态 TCP连接中包含不同的状态,如何通过状态来判断程序问题尤为重要. 三次握手 图中的connection部分为三次握手. 四次握手 图中的close部分为四次握手. CLOSE_WAIT 服 ...