方法一
- 每一个字母,用双指针查询最长回文
- 区分奇偶:唯一区别 k = i 或者 k = i + 1
var longestPalindrome = function (s) {
let res = '';
for (let i = 0; i < s.length; i++) {
for (let j = i, k = i; j >= 0 && k < s.length && s[j] === s[k]; j-- , k++) {
if (res.length < k - j + 1) res = s.substr(j, k - j + 1);
}
for (let j = i, k = i + 1; j >= 0 && k < s.length && s[j] === s[k]; j-- , k++) {
if (res.length < k - j + 1) res = s.substr(j, k - j + 1);
}
}
return res;
};
方法二:Manacher算法
- 马拉车局限性太大,只适用于最长回文字串,不建议学习
ma na cher马拉车名字来源
leetcode 地址
s字符串奇偶问题,加入#解决
奇回文串
aba
#a#b#a#
偶回文串
abba
#a#b#b#a#
变量
id: 容纳节点i最大回文子串的中心位置mx: 上一个对称轴+它的回文半径p: 回文半径数组
核心代码分析
p[i] = mx > i ? Math.min(p[2 * id - i], mx - i) : 1;
解释:
- 当
mx > i,说明i在上一个元素回文半径内,那i就对应一个j - 通过对称性得到对称点
j = 2 * id - i- 验证:
id = 3, i = 4, j = 2, j = 2 * 3 - 4 = 2
- 验证:
p[2 * id - i],是j的对称半径,mx - i是 以i对对称中心的对称半径- 比较
Math.min(p[2 * id - i], mx - i) p[2 * id - i] > mx - i, 说明j的对称半径大于了mx,即超过了mx,只能截取mx之内的,即是mx-i- 反之
p[2 * id - i] < mx - i,说明j的回文半径在mx之内,所以p[i]取p[2 * id - i] - 即
p[i]肯定是回文的,然后左右判断,是否回文,再++ - 通过对称性,拿到
j的回文半径,相当于用了缓存临时变量
p[i] + i > mx
- 保留最大的回文半径的对称点赋值
id,上一个回文对称点+回文半径mx
代码
function longestPalindrome(s) {
let str = s.split('').reduce((prev, item) => prev + item + '#', '#');
let id = 0, mx = 0, p = [];
let newLen = str.length;
// p = [x,x] 存的index的回文半径,mx 是上一个元素+回文半径
for (let i = 0; i < newLen; i++) {
p[i] = mx > i ? Math.min(p[2 * id - i], mx - i) : 1;
// i + p[i] 与 i - p[i], 左右对比,p[i]作为一个变量增长
// 控制左右是否溢出
while (
str[i + p[i]] === str[i - p[i]]
&& i - p[i] >= 0
&& i + p[i] < newLen
) { p[i]++ }
if (p[i] + i > mx) {
id = i;
mx = id + p[i];
}
}
const c_index = p.findIndex(it => Math.max(...p) === it);
const s_str = str.slice(c_index - (p[c_index] - 1), c_index + p[c_index]);
return s_str.replace(/\#/g, '');
}
注意点:
- 我存数组长度是,用
let size = str.length,关键字在leetcode里面报内部错误,😓 - 语文不好,表述更差,如有理解不到位的地方,请指出