最长回文子串-LeetCode 5 Longest Palindromic Substring
题目描述
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
即给定一个字符串,求它的最长回文子串的长度(或者最长回文子串)。
解法一
对于一个问题,一定可以找到一个傻的可爱的暴力解法,本题的暴力解法即:遍历整个字符串,以每一个字符为中心寻找以该字符为中心的最长回文子串,一次遍历下来即可获取最长回文子串,但是相应的这种方法的复杂度很糟糕O(N2)
这里值得注意的是要分开处理字符串长度为奇数或者偶数的情况
代码如下:
public String longestPalindrome(String s) {
String max = "";
int len = s.length();
for (int i = 0; i < len; i++) {
int odd = 0;
for (int j = 1; i + j < len && i >= j; j++) {
if (s.charAt(i + j) == s.charAt(i - j))
++odd;
else
break;
}
if (2 * odd + 1 > max.length())
max = s.substring(i - odd, i + odd + 1);
int even = 0;
for (int j = 1; i + j + 1 < len && i >= j; j++) {
if (s.charAt(i + j + 1) == s.charAt(i - j))
++even;
else
break;
}
if (even * 2 + 2 > max.length())
max = s.substring(i - even, i + even + 2 > s.length() ? s.length() : i + even + 2);
}
return max;
}
解法二
OK,笨的方法找到了,怎么样去提高效率。观察上面遍历的过程,对于字符串S,当以第i个字符为中心时,我们需要重新计算其最长回文子串,每个都是重头开始计算,那么能否利用回文字符串的性质来减少这种计算量从而提高整个算法的效率?答案是肯定的,下面要说的Manacher's 算法就是这样
统一奇偶
在正式开始算法之前,能否有一个方法将奇偶两种情况统一起来?为了达到这个目的,我们可以将原字符串S每个字符之间插入一个特殊字符'#',得到一个新的字符串T,如下
- S = "abaaba", T = "#a#b#a#a#b#a#".
这样可以发现无论长度奇偶都转换为奇情况来处理
Manacher算法
开头提到的思想,当我们要找寻以Tj为中心的回文子串时,能否利用前面已经算出的以Ti(i<j)为中心的回文子串,所以我们将前面算出的中间结果存入数组P,P[i]表示已Ti为中心的回文子串的长度(不包括其自身),而最长回文子串的长度就是P中的最大值。我们接着上面的例子

我们通过字符串T将对应的P写出,由于P6 = 6,可以很容易得出最长回文子串是"abaaba"
那么我们现在的关注点就主要放在如何计算P上,当然利用解法一那样我们可以通过遍历每一个点作为中心点来获取P,但是效率很低。还是前面提到的那个思想,当计算到第i个点作为中心点时,能否利用前面已经计算过的点。
观察回文串"abaaba"所对应的P,我们可以发现一条有用的规律,以i = 6作为中心,P中的数据时关于这个中心对称的,这不是偶然,我们可以尝试"aba",我们可以发现相似的对称性质。如果这条性质可以使用,我们就可以减少重复计算P的值。
为了验证这个思想,我们举一个稍微复杂一些的例子,S = "babcbabcbaccba",我们以图展现部分计算P的过程,从中找寻规律:

假设我们已经计算出一部分P的值,图中实线表示回文子串"abcbabcba"的中心位置,而虚线则表示该子串的左右边界
现在当我们想要计算i=13时P的值,已知i关于C的对称点i',我们怎样快速求出P[ i ]?
图中给出了我们的算法进行到i = 13的时候,我们需要计算P[ 13 ],我们来观察i关于回文子串中心点C的对称点i‘ = 9

图中我们用绿线标出了分别以i'和i为中心的回文子串,可以发现由于关于C点的对称性质,很容易得出P[ i ] = P[ i' ] = 1
通过以上分析,由于关于C的对称性质,我们很开心的得出一个结论P[ i ] = P[ i' ] = 1,而且之后的三个元素也都可以利用这条性质得出P的值(P[ 12 ] = P[ 10 ] = 0, P[ 13 ] = P[ 9 ] = 1, P[ 14 ] = P[ 8 ] = 0)

现在我们需要计算P[ 15 ],而i = 15关于C的对称点是i' = 7,那么p[ 15 ] = P[ 7 ] = 7?
当我们需要计算i = 15的时候,我们利用上面总结出的规律可以得出P[ 15 ] = P[ 7 ] = 7,但是进一步去计算P[ 15 ] 我们会发现以i = 15为中心点的最长回文子串是"a#b#c#b#a",事实是P[ 15 ] 要比对称点的子串短,这是为什么呢?

图中我们将以i'和以i为中心的子串用线标出,其中以绿线标出了严格根据中心点C对称的部分,而红线标出了超出
以C为中心点的子串的左右边界的部分,绿色的虚线部分标出了跨过中心点的部分
我们可以很清晰的发现,两个子串在绿色线标出的地方是完全对称的,同样绿色虚线部分由于中心对称也是满足的。然而P[ i' ] = 7,所以以i'为中心的子串超出了左边界,则这部分不再满足对称性质。我们只是知道P[ i ] ≥ 5,即i到右边界的长度。为了进一步得出P[ i ] 的值,我们需要向右扩展,在这里,由于P[ 21 ] ≠ P[ 7 ],所以P[ i ] = 5
我们总结一下上面发现的规律:
如果P[ i' ] ≤ R - i
那么 P[ i ] = P[ i' ]
否则 P[ i ] ≥ R - i (之后我们需要扩展出右边界来找到最终的P[ i ])
另外我们需要判断一下什么时候移动中心点C以及其右边界R
当以i为中心点的回文子串超出了右边界R时,我们将C移至i,将右边界R移至i的右边界
AC代码如下
private String insert(String s){
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
sb.append('#');
sb.append(s.charAt(i));
}
sb.append('#');
return sb.toString();
}
public String longestPalindrome(String s) {
String t = insert(s);
int[] p = new int[t.length()];
int c = 0, r = 0; // 当前中心位置以及当前中心位置的右边界
for (int i = 0; i < t.length(); i++) {
int i_mirror = 2 * c - i;
p[i] = r > i ? Math.min(r - i, p[i_mirror]) : 0;
while (i + p[i] + 1 < t.length() && i - p[i] - 1 >= 0
&& t.charAt(i + p[i] + 1) == t.charAt(i - p[i] - 1))
p[i]++;
if (i + p[i] > r) {
c = i;
r = i + p[i];
}
}
int maxC = 0;
for (int i = 0; i < t.length(); i++) {
if (p[i] > p[maxC])
maxC = i;
}
return t.substring(maxC - p[maxC], maxC + p[maxC]).replace("#", "");
}
由于我们有两个变量中心点C以及右边界R,当P[ i ] ≤ R – i,我们直接以O(1)进行计算,而另一种情况则需要移动中心点和右边界,最多两者都是移动N步,所以总的时间负责度时O(2*N)即O(N)
——reference
Longest Palindromic Substring Part II
最长回文子串-LeetCode 5 Longest Palindromic Substring的更多相关文章
- 求最长回文子串 - leetcode 5. Longest Palindromic Substring
写在前面:忍不住吐槽几句今天上海的天气,次奥,鞋子里都能养鱼了...裤子也全湿了,衣服也全湿了,关键是这天气还打空调,只能瑟瑟发抖祈祷不要感冒了.... 前后切了一百零几道leetcode的题(sol ...
- 动态规划—最长回文子串LEETCODE第5题深度剖析
动态规划对于笔者来说有很重要的意义 一.题目如下: 对于此类题目,笔者常用的的办法是先做个暴力解题思路,然后再对暴力法进行优化. 二.暴力法 //字串遍历 public static String l ...
- Leetcode 5. Longest Palindromic Substring(最长回文子串, Manacher算法)
Leetcode 5. Longest Palindromic Substring(最长回文子串, Manacher算法) Given a string s, find the longest pal ...
- [LeetCode] 5. Longest Palindromic Substring 最长回文子串
Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...
- 【LeetCode】5. Longest Palindromic Substring 最长回文子串
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:最长回文子串,题解,leetcode, 力扣,python ...
- LeetCode:Longest Palindromic Substring 最长回文子串
题目链接 Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...
- leetcode 5 :Longest Palindromic Substring 找出最长回文子串
题目: Given a string S, find the longest palindromic substring in S. You may assume that the maximum l ...
- [leetcode]5. Longest Palindromic Substring最长回文子串
Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...
- [译+改]最长回文子串(Longest Palindromic Substring) Part II
[译+改]最长回文子串(Longest Palindromic Substring) Part II 原文链接在http://leetcode.com/2011/11/longest-palindro ...
随机推荐
- Apache Ignite之集群应用测试
集群发现机制 在Ignite中的集群号称是无中心的,而且支持命令行启动和嵌入应用启动,所以按理说很简单.而且集群有自动发现机制感觉对于懒人开发来说太好了,抱着试一试的心态测试一下吧. 在Apache ...
- 移动端IOS点击事件失效解决方案
解决方案 解决办法有 4 种可供选择: 1 将 click 事件直接绑定到目标元素(即 .target)上 2 将目标元素换成 <a> 或者 button 等可点击的元素 3 将 clic ...
- 【WCF】错误协定声明
在上一篇烂文中,老周给大伙伴们介绍了 IErrorHandler 接口的使用,今天,老周补充一个错误处理的知识点——错误协定. 错误协定与IErrorHandler接口不同,大伙伴们应该记得,上回我们 ...
- 神经网络、logistic回归等分类算法简单实现
最近在github上看到一个很有趣的项目,通过文本训练可以让计算机写出特定风格的文章,有人就专门写了一个小项目生成汪峰风格的歌词.看完后有一些自己的小想法,也想做一个玩儿一玩儿.用到的原理是深度学习里 ...
- GPG终极指南(加密/签名)
我们平时都听过非对称加密,公钥和私钥,签名验证,但这些证书都是怎么得到的呢?本篇文章会解答这些问题. 背景介绍 加密的一个简单但又实用的任务就是发送加密电子邮件.多年来,为电子邮件进行加密的标准一直是 ...
- 使用Expression实现数据的任意字段过滤(1)
在项目常常要和数据表格打交道. 现在BS的通常做法都是前端用一个js的Grid控件, 然后通过ajax的方式从后台加载数据, 然后将数据和Grid绑定. 数据往往不是一页可以显示完的, 所以要加分页: ...
- bash字符串操作
参考 http://www.cnblogs.com/chengmo/archive/2010/10/02/1841355.html 问题:bash怎么提取字符串的最后一位?例如python中strin ...
- 用django创建一个项目
首先你得安装好python和django,然后配置好环境变量,安装python就不说了,从配置环境变量开始 1.配置环境变量 在我的电脑处点击右键,或者打开 控制面板\系统和安全\系统 -> 左 ...
- #26 fibonacci seqs
Difficulty: Easy Topic: Fibonacci seqs Write a function which returns the first X fibonacci numbers. ...
- 第14章 Linux启动管理(2)_启动引导程序grub
2. 启动引导程序grub 2.1 Grub配置文件 (1)grub中分区的表示 硬盘 分区 Linux设备文件名 Grub中设备文件名 第1块SCSI硬盘 第1个主分区 /dev/sda1 hd(0 ...