给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示:
1 <= s.length <= 1000
s 仅由数字和英文字母组成
思路就是马拉车这个算法,对我来说实现的难度主要是在如何用java写,java的string类用的还是不熟练欸。
首先介绍一下马拉车算法,作为一个比较冷门的字符串处理方法,理解起来难度比好多了。
首先我们考虑这样一个问题,就是回文子串的长度分为两种, 一种是奇数,一种是偶数。
如果是奇数的话就是这样的: ababa
如果是偶数的话就是这样的: aabbaa
但是如果是偶数的话,我们确实不方便处理,因此我们首先考虑如何吧偶数串,转化为奇数串?
我们的方法是,在收尾添加两个不同的字符,然后每个原有的字符前面后面都加一个#号。
这样我们的字符串:比如说奇数的aba就变成了¥#a#b#b#a#^
这样我们的回文字符串就变成了#a#b#b#a#是个奇数
- void init()
- {
- int k = 0;
- b[k ++ ] = '$', b[k ++ ] = '#';
- for (int i = 0; i < n; i ++ ) b[k ++ ] = a[i], b[k ++ ] = '#';
- b[k ++ ] = '^';
- n = k;
- }
然后我们需要求一个叫p[i]的数组
p代表着转化后的字符串的”半径“
#a#b#b#a#的半径就是#a#b#长度为5, 里面一共有5 - 1个字符, 也就代表着,我们原来的字符串长度为4;
那么问题来了,我们如何求这个p呢?
首先我们要明确这样一件事情,p数组对应的字符串是我们插入#后的字符串, p[i] - 1对应的就是该回文子串在原来字符串的长度
p[i]表示的是以新字符串b[i]为中心的最长回文子串最右字符到b[i]的距离,也包括b[i]
计算,我们首先要引入两个变量,一个是mid, 一个是mr;
mid表示最大回文串中心的位置,
mr = id + p[id], 代表最大回文子串的有边界
我们要分情况讨论,根据,i和mr的关系来确定。
第一种是i 第二种是i>= mr; 第一种情况由于我们的i已经小于mr了,说明,在我们当前的最大回文子串 p[mid]中,也有一个p[j]==p[i], 而且由于他俩是对称的,所以会导致:i + j == 2 * mid; 我们就求得j = 2 * mid - i; 这时候我们就要考虑如何用p[j]去更新p[i] i 我们现在的i距离mr的距离是mr - i; 如果p[j] > mr - i; 说明 以 j为中心的回文子串, 左边已经超出了 我们当前最大回文子串的左边界,由于这个回文串对称性, 我们可以知道如果让p[i]等于p[j]的话,当前的条件是,p[i]右边超出mr的那一部分也必须是回文串的一部分,但是这一部分又难以预料,我们还没有求,所以说, p[j] > mr - i; 的情况下,p[i]就是等于mr - i; 但是如果p[j] <= mr - i;说明,当前j 为中心的回文子串,全部都在最大回文串的内部,对称性可知,这时候的p[i] == p[j]; 再去处理i>= mr;的情况 由于我们i已经大于mr了,外边的都没有匹配到p[mid]里面去,我们只能暂时让p[i]等于一 最后我们为了解决 i < mr && p[i] > mr - i;和 i >= mr 的情况,我们只能采取向两边拓展的方式: 最后更新mr和mid; 如果i + p[i] > mr, 说明说明以i为中心的回文字串超过的边界mr, 就需要更新 最后是总结一下java用到的函数: String的charAt Math.min(); s.substring(); ok跑路,写了好久这篇哈哈哈while (b[i - p[i]] == b[i + p[i]]) p[i] ++;