博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
求最长回文子串 - leetcode 5. Longest Palindromic Substring
阅读量:6907 次
发布时间:2019-06-27

本文共 2147 字,大约阅读时间需要 7 分钟。

写在前面:忍不住吐槽几句今天上海的天气,次奥,鞋子里都能养鱼了...裤子也全湿了,衣服也全湿了,关键是这天气还打空调,只能瑟瑟发抖祈祷不要感冒了....

前后切了一百零几道的题(solution同步在),主要是拣难度系数定为easy的水题做...好吧,这是第一道算法题。不知哪位大神说的,所有的语言都会过时,只有数据结构和算法才是永恒。

今天要重点讲的是优雅的Manacher算法,先来看这道题,题目很简单,给你一个字符串,找到最长的回文子串。啥叫回文串?就是前后看都一样的串,比如abcbaabba,因为题目给的数据量不大(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 sfunction 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;};

转载地址:http://cvgdl.baihongyu.com/

你可能感兴趣的文章
软链接和硬链接
查看>>
android左侧滑效果
查看>>
Check_mk 主机状态为 down 但是主机下其他服务有数据且正常 解决方法
查看>>
解决重装 Windows 后进入不了 Linux
查看>>
获取系统串口号
查看>>
redis 并发处理,多线程以及synchronized锁的应用
查看>>
Ubuntu安装OpenSSL
查看>>
检查HP服务器内存状态脚本
查看>>
string.punctuation
查看>>
Linux运维 第二阶段 (十二) 进程管理
查看>>
在MWC2018上看工业互联网走向
查看>>
互联网产品常用英语单词
查看>>
实验一 分治与递归—用分治法实现元素选择 java算法
查看>>
Linux常用命令大全(归类)
查看>>
HMGET key field [field ...]
查看>>
shell习题-判断函数
查看>>
Redis Modules: an introduction to the API
查看>>
centos ip使用
查看>>
influxdb查询写入操作
查看>>
linux命令——mv
查看>>