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 ...
随机推荐
- bzoj3674同上(好短)
+强在 就过了 既没有启发式又没有路径压缩,连建树都用的是代码最短的写法(什么心态,每天追求代码短) 话说回来 可持久化的数组感觉只能出类似裸题的题目,,,,藏也藏不住啊 #include <c ...
- TDD测试驱动开发
TDD测试驱动开发 一.概念 TDD故名思意就是用测试的方法驱动开发,简单说就是先写测试代码,再写开发代码.传统的方式是先写代码,再测试,它的开发方式与之正好相反. TDD是极限编程的一个最重要的设计 ...
- Django 权限管理
对于Django而言,虽然自带了一些基本的通用权限限制,但现实中,可能我们更希望自己去定义业务权限划分 Django对于权限这块的部分验证方法 user = request.user user.is_ ...
- VS2010 ERROR:c1xx fatal error c1083
在VS2010中新建文件夹,然后在文件夹内新建文件polling.cpp,可是在项目中不现实该cpp文件,所以就在在硬盘上将该文件删除,编译报错. >c1xx : fatal error C10 ...
- [LintCode] Linked List Cycle 单链表中的环
Given a linked list, determine if it has a cycle in it. ExampleGiven -21->10->4->5, tail co ...
- .Net程序员之不学Java做安卓开发:奇怪的Java语法
1.final关键字:用以修饰类时,表示类不可以被继承,指向基本数据类型或者引用类型时,该类只可以在声明的时候初始化 2.@Override 类似C# 中override关键字,表示对父类的重写.网上 ...
- 使用--gc-section编译选项减小程序体积
本周在给程序添加功能的时候,突然发现,我只是写了几个函数,还没调用,size就变大了.这肯定是不行的嘛,没用的函数就应该不链接进来,占用我宝贵的空间. 这种功能,讲道理编译器肯定要支持的,于是搜了一下 ...
- Android 6.0 使用HttpURLConnection 使用Get提交遇到405等问题。
HttpURLConnection 在调用connection.setDoOutput(true)之后会自动把提交方式改为POST.然后调用方法的时候有可能会出现这种情况 在调用get的时候设置为co ...
- web api Route属性定义
ASP.NET Web API路由,简单来说,就是把客户端请求映射到对应的Action上的过程.在"ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置"一 ...
- ApexSQLLog可以只读取ldf文件
ApexSQLLog可以只读取ldf文件 需要数据库在线 本文版权归作者所有,未经作者同意不得转载.