求最长回文子串 - leetcode 5. Longest Palindromic Substring
写在前面:忍不住吐槽几句今天上海的天气,次奥,鞋子里都能养鱼了...裤子也全湿了,衣服也全湿了,关键是这天气还打空调,只能瑟瑟发抖祈祷不要感冒了....
前后切了一百零几道leetcode的题(solution同步在github),主要是拣难度系数定为easy的水题做...好吧,这是第一道算法题。不知哪位大神说的,所有的语言都会过时,只有数据结构和算法才是永恒。
今天要重点讲的是优雅的Manacher算法
,先来看这道题Longest Palindromic Substring,题目很简单,给你一个字符串,找到最长的回文子串。啥叫回文串?就是前后看都一样的串,比如abcba
,abba
,因为题目给的数据量不大(1000),所以可以枚举字符串的每个位置当做回文对称点,回文对称点是我给它的一个概念,比如abcba
的回文对称点就是idx=2也就是c的位置。But!并不是每个回文串都有对称点,比如abba
,只有对称轴,它就没有点!怎么办?机智的coder想出了一个简单的用空间换取代码实现复杂度的方法,这也是Manacher算法的第一步:
abcba -> #a#b#c#b#a#
abba -> #a#b#b#a#
这么一来,每个回文串就都有回文对称点了(可能是字母,也可能是#)。之后我们就能枚举对称点,然后向两边扩散开去,比较字符是否一样。为了不用判断是否已经到了边界,我们最初在字符串的开头再加个字符*
,只要该字符和#
以及字符串里其他字符都不一致即可。这样是可以AC的,虽然复杂度达到了O(n^2)。接下去我们介绍复杂度为O(n)的Manacher算法。
我们试着以字符串babcbade
举例,首先把字符串像上面一样变形:
babcbade -> *#b#a#b#c#b#a#d#e#
然后我们设置一个dp数组,dp[i]表示以变形后第i个元素为对称点的最长回文子串的半径,同样以上面的字符串举例,可以得到dp数组:
*#b#a#b#c#b#a#d#e#
112121216121212121
我们可以很容易地发现,要求的最长回文子串的长度即dp数组最大值减去1。于是如何快速地求得该数组成为关键。假设我们已经得到了dp[6]的值,dp[10]的初始值也不难确定,因为它们两个元素根据idx=8对称(#a#b#c#b#a#),所以可以不用从1开始向两边扩散了。
我们用maxn
维护当前存在的回文子串能达到最右的位置+1(maxn位置不可达到),用idx
维护当前能到达最右+1的回文子串的回文中心点位置,实现该dp数组求值的核心代码如下:
for (var i = 1, len = str.length; i < len; i++) {
if (maxn > i) dp[i] = Math.min(dp[2 * idx - i], maxn - i);
else dp[i] = 1;
while (str[i - dp[i]] === str[i + dp[i]]) dp[i]++;
if (dp[i] + i > maxn)
maxn = dp[i] + i, idx = i;
}
完整的AC代码:
// return the Longest Palindromic Substring of s
function Manacher(s) {
var str = '*#'
, dp = []
, maxn = 0
, idx = 0;
for (var i = 0, len = s.length; i < len; i++)
str += s[i] + '#';
for (var i = 1, len = str.length; i < len; i++) {
if (maxn > i) dp[i] = Math.min(dp[2 * idx - i], maxn - i);
else dp[i] = 1;
while (str[i - dp[i]] === str[i + dp[i]]) dp[i]++;
if (dp[i] + i > maxn)
maxn = dp[i] + i, idx = i;
}
var ans = 0
, pos;
for (var i = 1; i < len; i++) {
if (dp[i] > ans)
ans = dp[i], pos = i;
}
var f = str[pos] === '#'
, tmp = f ? '' : str[pos]
, startPos = f ? pos + 1 : pos + 2
, endPos = f ? dp[pos] - 3 + startPos : dp[pos] - 4 + startPos;
for (var i = startPos; i <= endPos; i += 2)
tmp = str[i] + tmp + str[i];
return tmp;
}
var longestPalindrome = function(s) {
var str = Manacher(s);
return str;
};
求最长回文子串 - leetcode 5. Longest Palindromic Substring的更多相关文章
- 最长回文子串-LeetCode 5 Longest Palindromic Substring
题目描述 Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...
- hdu 3068 最长回文(manachar求最长回文子串)
题目连接:hdu 3068 最长回文 解题思路:通过manachar算法求最长回文子串,如果用遍历的话绝对超时. #include <stdio.h> #include <strin ...
- PAT甲题题解-1040. Longest Symmetric String (25)-求最长回文子串
博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6789177.html特别不喜欢那些随便转载别人的原创文章又不给 ...
- Manacher模板( 线性求最长回文子串 )
模板 #include<stdio.h> #include<string.h> #include<algorithm> #include<map> us ...
- 求最长回文子串:Manacher算法
主要学习自:http://articles.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html 问题描述:回文字符串就是左右 ...
- 后缀数组 - 求最长回文子串 + 模板题 --- ural 1297
1297. Palindrome Time Limit: 1.0 secondMemory Limit: 16 MB The “U.S. Robots” HQ has just received a ...
- Manacher算法 O(n) 求最长回文子串
转自:http://bbs.dlut.edu.cn/bbstcon.php?board=Competition&gid=23474 其实原文说得是比较清楚的,只是英文的,我这里写一份中文的吧. ...
- Manacher算法——求最长回文子串
首先,得先了解什么是回文串.回文串就是正反读起来就是一样的,如“abcdcba”.我们要是直接采用暴力方法来查找最长回文子串,时间复杂度为O(n^3),好一点的方法是枚举每一个字符,比较较它左右距离相 ...
- manacher算法求最长回文子串
一:背景 给定一个字符串,求出其最长回文子串.例如: s="abcd",最长回文长度为 1: s="ababa",最长回文长度为 5: s="abcc ...
随机推荐
- ORACLE查看表空间对象
ORACLE如何查看表空间存储了那些数据库对象呢?可以使用下面脚本简单的查询表空间存储了那些对象: SELECT TABLESPACE_NAME AS TABLESPACE_NAME ...
- mvc razor中renderPartial,RenderAction,Partial,Action的使用选择
RenderPartial: 通常被用来显示一个功能相对独立的“块”,比如说显示菜单或者导航条. RenderPartial输出的结果被作为调用的View的一部分显示. 这个方法会直接将结果写入到当前 ...
- oracle学习笔记系列------oracle 基本操作之表的增删改查
--创建一个表 CREATE TABLE employee_souvc( id ), name ), gender ), birth DATE, salary ,), job ), deptno ) ...
- Linux系统监控命令之iotop
iotop命令 iotop命令是一个用来监视磁盘I/O使用状况的top类工具.iotop具有与top相似的UI,其中包括PID.用户.I/O.进程等相关信息.Linux下的IO统计工具如iostat, ...
- Android设置AlertDialog点击按钮对话框不关闭(转)
(转自:http://blog.csdn.net/winson_jason/article/details/8485524) 当我们在用到Android alertDialog创建对话框 的时候,我们 ...
- Nova 操作汇总(限 libvirt 虚机) [Nova Operations Summary]
本文梳理一下 Nova 主要操作的流程. 0. Nova REST-CLI-Horizon 操作对照表 Nova 基本的 CRUD 操作和 extensions: # 类别 Nova V2 REST ...
- Markdown learning
For details, please refer to Markdown # Markdown Learning #h1 ##h2 ###h3 ####h4 **Bond** *italic* Th ...
- Java开发之Servlet之间的跳转
一.转向(Forward) 1.要点说明 转向是通过RequestDispatcher对象的forward()方法来实现的.RequestDispatcher可以通过HttpServletReques ...
- Excel实用操作
目地 不能熟练操作Excel的程序员不是好策划. 一片区域填充相同数据 1.用鼠标框选一片区域,松开鼠标,不要点其它单元格 2.直接输入输入数据,输完之后,按Ctrl+Enter,选中的区域就会填充相 ...
- 嵌入式Linux驱动学习之路(三)u-boot配置分析
u-boot配置流程分析 执行make tiny4412_config后,将会对u-boot进行一些列的配置,以便于后面的编译. 打开顶层目录下的Makefile,查找对于的规则tiny4412_co ...