给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
示例 1:
输入: “babad”
输出: “bab”
注意: "aba"也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
思路
这道题很显然可以用暴力求解,但时间复杂度太高,也起不到刷题的训练作用。搜了一下,全是关于manacher的算法。看了好久才弄懂的。写这篇也是来巩固梳理一下(其他人写的好多代码很难懂!)希望读者有耐心读完!
理论
回文可能是奇数:‘aba’;也可能是偶数:‘abba’,最节省时间的判断回文方法是从中间开始向两边判断,但偶数个数的回文字符串就不行了。于是——Manacher就想到,在所有字符中间添加一个占位的符号(例如’#’,必须不是原始字符串中的字符),这样 ‘abba’ 就变为 ‘#a#b#b#a#’,就可以从中间的 ‘#’ 开始想两边延申啦。
所以,第一步就是将原始字符串 'abba' 变化为含有 '#' 的字符串 '#a#b#b#a#'
s = '#' + s.split('').join('#') + '#';
接下来,就要循环遍历了。以每个字符为中心,向两边延申直到不相等,延申长度为 radius,
第二步,设置变量:
let radius = 0;
还要设置一个最大半径,用来保存回文的最大半径,和保存最长子串的subString
let maxRadius = 0;
let subString = '';
当radius大于maxRadius时,说明该更新了,同时,要保存最长子串 subString
subString = s.slice(i - radius + 1, i + radius);
遍历完后,别忘了把子串中的所有’#’ 去掉
while (subString.includes('#')) {
subString = subString.replace('#', '')
}
全部代码:
/**
* @param {string} s
* @return {string}
*/
var longestPalindrome = function(s) {
s = '#' + s.split('').join('#') + '#';
let radius = 0;
let maxRadius = 0;
let subString = '';
for (let i = 0; i < s.length ; i ++) {
radius = 1
while (s[i - radius] === s[i + radius] && s[i - radius] !== undefined) {
radius ++;
}
if (radius > maxRadius) {
subString = s.slice(i - radius + 1, i + radius);
maxRadius = radius;
}
}
while (subString.includes('#')) {
subString = subString.replace('#', '')
}
return subString;
};
PS:这是简单精简版!也能通过测试,原版的更加优化快速,但我已无力!