题目来自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算法)的更多相关文章

  1. 九度OJ 1528 最长回文子串 -- Manacher算法

    题目地址:http://ac.jobdu.com/problem.php?pid=1528 题目描述: 回文串就是一个正读和反读都一样的字符串,比如"level"或者"n ...

  2. 最长回文子串—Manacher 算法 及 python实现

    最长回文子串问题:给定一个字符串,求它的最长回文子串长度.如果一个字符串正着读和反着读是一样的,那它就是回文串.   给定一个字符串,求它最长的回文子串长度,例如输入字符串'35534321',它的最 ...

  3. hihocoder #1032 : 最长回文子串 Manacher算法

    题目链接: https://hihocoder.com/problemset/problem/1032?sid=868170 最长回文子串 时间限制:1000ms内存限制:64MB 问题描述 小Hi和 ...

  4. 5. Longest Palindromic Substring(最长回文子串 manacher 算法/ DP动态规划)

    Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...

  5. HiHo 1032 最长回文子串 (Manacher算法求解)

    /** * 求解最长回文字串,Manacher算法o(n)求解最长回文子串问题 **/ #include<cstdio> #include<cstdlib> #include& ...

  6. hihoCoder #1032 : 最长回文子串 [ Manacher算法--O(n)回文子串算法 ]

    传送门 #1032 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相 ...

  7. 51nod1089 最长回文子串 manacher算法

    0. 问题定义 最长回文子串问题:给定一个字符串,求它的最长回文子串长度. 如果一个字符串正着读和反着读是一样的,那它就是回文串.下面是一些回文串的实例: 12321 a aba abba aaaa ...

  8. 最长回文子串Manacher算法模板

    Manacher算法能够在O(N)的时间复杂度内得到一个字符串以任意位置为中心的回文子串.其算法的基本原理就是利用已知回文串的左半部分来推导右半部分. 首先,在字符串s中,用rad[i]表示第i个字符 ...

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

    回文串包括奇数长的和偶数长的,一般求的时候都要分情况讨论,这个算法做了个简单的处理把奇偶情况统一了.算法的基本思路是这样的,把原串每个字符中间用一个串中没出现过的字符分隔开来(统一奇偶),用一个数组p ...

随机推荐

  1. 使用poco 的NetSSL_OpenSSL 搭建https 服务端,使用C++客户端,java 客户端访问,python访问(python还没找到带证书访问的代码.)

    V20161028 由于项目原因,需要用到https去做一些事情. 这儿做了一些相应的研究. 这个https 用起来也是折腾人,还是研究了一周多+之前的一些积累. 目录 1,java client 通 ...

  2. linux进程后台运行及输出重定向

    本机环境为ubuntu 14.04 以ping www.baidu.com为例: 1.程序的前台运行 ping www.baidu.com 可以看到,屏幕上输出了baidu返回的结果 2.实现程序后台 ...

  3. WebP 原理和 Android 支持现状介绍(转)

    本文为腾讯Bugly开发者社区 投稿,作者:soonlai,版权归原作者所有,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/582939577ef9c5b70855 ...

  4. 打造AngularJs2.0开发环境

    angularjs2.0刚发布, typescript2.0也刚发布, 于2016.9.29记录. 参考文档:https://angular.cn/docs/ts/latest/quickstart. ...

  5. 字典NSDictionary以及NSMutableDictionary的用法总结

    做过Java语言 或者 C语言 开发的朋友应该很清楚 关键字map 吧,它可以将数据以键值对儿的形式储存起来,取值的时候通过KEY就可以直接拿到对应的值,非常方便.在Objective-C语言中 词典 ...

  6. PYTHON黑帽编程1.5 使用WIRESHARK练习网络协议分析

    Python黑帽编程1.5  使用Wireshark练习网络协议分析 1.5.0.1  本系列教程说明 本系列教程,采用的大纲母本为<Understanding Network Hacks At ...

  7. 写一个脚本,自动启动tomcat

    我的服务器是使用tomcat的,时不时tomcat的进程会突然结束掉,不知道为什么,从日志上看也没有任何可疑之处,貌似就这样突然没了,接下来的日志都是重新启动tomcat之后打印的了.原因找不到,但要 ...

  8. 多线程中的锁系统(二)-volatile、Interlocked、ReaderWriterLockSlim

    上章主要讲排他锁的直接使用方式.但实际当中全部都用锁又太浪费了,或者排他锁粒度太大了,本篇主要介绍下升级锁和原子操作. 阅读目录 volatile Interlocked ReaderWriterLo ...

  9. MySQL 存储过程和函数

    概述 一提到存储过程可能就会引出另一个话题就是存储过程的优缺点,这里也不做讨论,一般别人问我我就这样回答你觉得它好你就用它.因为mysql中存储过程和函数的语法非常接近所以就放在一起,主要区别就是函数 ...

  10. TCP状态

    TCP状态 TCP连接中包含不同的状态,如何通过状态来判断程序问题尤为重要. 三次握手 图中的connection部分为三次握手. 四次握手 图中的close部分为四次握手. CLOSE_WAIT 服 ...