题目来自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. Python几种常用的测试框架

    一.测试的常用规则 一个测试单元必须关注一个很小的功能函数,证明它是正确的: 每个测试单元必须是完全独立的,必须能单独运行.这样意味着每一个测试方法必须重新加载数据,执行完毕后做一些清理工作.通常通过 ...

  2. 谷歌浏览器如何查看或获取Cookie字符串

    注:此博客仅供非web开发人员查看,以下内容都基于谷歌浏览器. 在网页空白处点击鼠标右键,在弹出菜单中选择[审查元素],可以看到网页下方出现审查元素相关界面. 在审查元素相关界面,点击[Network ...

  3. 初识linux

    1.版本 稳定版本:偶数版如2.6.X 发展中的版本:奇数版如2.5.X linux distribution包含:linux kernel + free software + documentati ...

  4. 踏上Salesforce的学习之路(一)

    相信通过前面的学习,大家已经拥有了一个属于自己的Salesforce开发者账号,下面,我们将用这个账号正式踏上Salesforce的学习之路. 首先,点击网址:https://developer.sa ...

  5. MongoDB 由于目标计算机积极拒绝,无法连接 2014-07-25T11:00:48.634+0800 warning: Failed to connect to 127.0.0.1:27017, reason: errno:10061

    转载自:http://www.cnblogs.com/xiaoit/p/3867573.html 1:启动MongoDB 2014-07-25T11:00:48.634+0800 warning: F ...

  6. swiper的初步使用

    1.引入文件,顺序引入(此处基于jquery,且版本至少1.7以上) <link rel="stylesheet" href="path/to/swiper-3.4 ...

  7. Nodejs Promise的一点记录

    项目需要,看了点nodejs,其中比较难理解的就是Promise了,记录一下学习bluebird提供的Promise实现. Promise.promisifyAll(obj)方法 作用:把对象的方法属 ...

  8. Html5 中的新语义标签

    1.1 语义标签对于我们并不陌生,如<p>表示一个段落.<ul>表示一个无序列表<h1> ~ <h6>表示一系列标题等,在此基础上HTML5增加了大量更 ...

  9. Struts2登录小例子

    前面实现了一个数据显示的例子,下面我来实现以下使用Struts2登录 首先是配置不用过多解释 注意名字要和类名保持一致 因为实现的是action这个方法所以需要用action.log来跳转到类里面 解 ...

  10. The easy way to implement a Red-Black tree

    Red-Black trees are notorious for being nightmares of pointer manipulation. Instructors will show th ...