给你一个字符串 s,找到 s 中最长的回文子串。
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/lo… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
1. 中心扩散法
以奇数长度回文串为例:
遍历字符串 , 对于每一个字符 , 定义
其中 表示回文串的最左端的下标, 表示回文串最右端的下标
每当 时, . 同时 表示回文子串的长度
var longestPalindrome = function(s) {
const n = s.length
let st = 0, len = 0
for (let i = 0, l, r; i < n; i ++) {
// odd
l = r = i
while (l >= 0 && r < n && s[l] === s[r]) {
l --, r ++
}
l ++, r --
if (len < r - l + 1) {
st = l, len = r - l + 1
}
// even
l = i, r = i + 1
while (l >= 0 && r < n && s[l] === s[r]) {
l --, r ++
}
l ++, r --
if (len < r - l + 1) {
st = l, len = r - l + 1
}
}
return s.slice(st, st + len)
};
2. Manacher
2.1 朴素 Manacher
指的是以 为中心的回文字符串(奇数)的一半(向上取整), 如 的
指的是以 为中心偏右的回文字符串(偶数)的一半, 如 的
var longestPalindrome = function(s) {
const n = s.length
const d1 = new Array(n).fill(0)
cosnt d2 = new Array(n).fill(0)
let st = 0, len = 0
for (let i = 0; i < n; i ++) {
d1[i] = 1
while (i - d1[i] >= 0 && i + d1[i] < n && s[i - d1[i]] === s[i + d1[i]]) {
d1[i] ++
}
d2[i] = 0
while (i - d2[i] - 1 >= 0 && i + d2[i] < n && s[i - d2[i] - 1] === s[i + d2[i]]) {
d2[i] ++
}
}
};
2.2 优化的 Manacher
遍历字符串 , 表示遍历到的当前项, 表示当前已知的所有回文串中最靠右的回文串.
- 如果 不在 的右侧, 则表明 在 之间. 对于 来说, 存在一个 与其在 中对称, 如下图所示:
此时对于 来说, 其 有两种可能:
- 如果以 为中心的回文子字符串的范围在 中, 那么
- 如果以 为中心的回文子字符串的范围超出了 , 则为 赋初始值: , 后再以朴素版 Manacher 对 进行求值
- 如果 在 的右侧, 则只能直接使用 Manacher 算法对 进行求值
var longestPalindrome = function(s) {
const n = s.length
const d1 = new Array(n + 1).fill(0)
const d2 = new Array(n + 1).fill(0)
let st = 0, len = 0
for (let i = 0, l = 0, r = -1, k; i < n; i ++) {
// odd
k = (i > r) ? 1 : Math.min(d1[l + r - i], r - i + 1)
while (i - k >= 0 && i + k < n && s[i - k] === s[i + k]) {
k ++
}
d1[i] = k --
if (r < i + k) {
l = i - k
r = i + k
}
// even
k = (i > r) ? 0 : Math.min(d2[l + r - i + 1], r - i + 1)
while (i - k - 1 >= 0 && i + k < n && s[i - k - 1] === s[i + k]) {
k ++
}
d2[i] = k --
if (r < i + k) {
r = i + k
l = i - k - 1
}
if (len < d2[i] * 2) {
st = i - d2[i], len = d2[i] * 2
}
if (len < d1[i] * 2 - 1) {
st = i - d1[i] + 1, len = d1[i] * 2 - 1
}
}
return s.slice(st, st + len)
};