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 ...
随机推荐
- web.xml配置错误导致applicationContext.xml配置重复加载
web.xml相关配置 <context-param><param-name>log4jRefreshInterval</param-name><param- ...
- centos7 搭建nginx和tomcat集成
一.安装jdk 1.yum install jdk 2.安装好了之后配置环境变量 在/etc/profile 二.创建项目运行目录 1. 我放在home目录 mkdir /web/webapps ...
- [LintCode] Intersection of Two Linked Lists 求两个链表的交点
Write a program to find the node at which the intersection of two singly linked lists begins. Notice ...
- android——fargment基础
1.Fragment的产生与介绍 Android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视.针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后拷贝一份,修改布局以适应 ...
- WebView解析
WebView解析 WebView是一个基于Webkit的,相当于内置浏览器的强大功能的组件,WebView的使用这么分四步说明:添加组件,加载资源,属性设置,辅助功能. 一.WebView的添加 ...
- c#多线程介绍(上)
转载原文:这里是链接内容 转载原文:这里写链接内容 转载原文:这里写链接内容 (重要事情说三遍) 引言 本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个 ...
- [转]ios push
转:http://blog.csdn.net/showhilllee/article/details/8631734 APNS的推送机制 首先我们看一下苹果官方给出的对ios推送机制的解释.如下图 P ...
- 基于ajax与msmq技术的消息推送功能实现
周末在家捣鼓了一下消息推送的简单例子,其实也没什么技术含量,欢迎大伙拍砖.我设计的这个推送demo是基于ajax长轮询+msmq消息队列来实现的,具体交互过程如下图: 先说说这个ajax长轮询,多长时 ...
- Backbone源码分析(三)
Backbone源码分析(一) Backbone源码分析(二) Backbone中主要的业务逻辑位于Model和Collection,上一篇介绍了Backbone中的Model,这篇文章中将主要探讨C ...
- 剑指Offer面试题:16.合并两个排序的链表
PS:这也是一道出镜率极高的面试题,我相信很多童鞋都会很眼熟,就像于千万人之中遇见不期而遇的人,没有别的话可说,唯有轻轻地问一声:“哦,原来你也在这里? ” 一.题目:合并两个排序的链表 题目:输入两 ...