题目描述
- 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
解答
暴力破解
外面的两层循环找到所有子串,第三层循环判断子串是否是回文。方法的时间复杂度为O(n^3),空间复杂度为O(1)。
var longestPalindrome = function(s) {
let n = s.length;
let result = ''
for(let i = 0;i<n;i++){
for(let j=i+1;j<=n;j++){
let str = s.slice(i,j);
let f = str.split('').reverse().join('');
if(str == f){
result = str.length > result.length ? str : result;
}
}
}
console.log(result);
return result;
};
动态规划
var longestPalindrome = function(s) {
let len = s.length;
let result;
let i,j,L;
let dp=Array(len).fill(0).map(x=>Array(len).fill(0));
//console.log(dp);
if(len<=1){
return s
}
// 只有一个字符的情况是回文
for(i = 0;i<len;i++){
dp[i][i] = 1
result = s[i]
}
// L是i和j之间的间隔数(因为间隔数从小到大渐增,所以大的间隔数总能包含小的间隔数)
// i j
// abcdcba.length = L 所以 L = j-i+1; => j = i+L-1;
for ( L = 2; L <= len; L++) {
// 从0开始
for ( i = 0; i <= len - L; i++) {
j = i + L - 1;
if(L == 2 && s[i] == s[j]) {
dp[i][j] = 1;
result = s.slice(i, i + L);
}else if(s[i] == s[j] && dp[i + 1][j - 1] == 1) {
dp[i][j] = 1
result = s.slice(i, i + L);
}
}
}
//console.log(result);
return result;
}
Manacher算法
首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个特殊的符号。比如 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。
然后用一个数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i],也就是把该回文串“对折”以后的长度),比如S和P的对应关系:
S # 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1 #
P 1 2 1 2 5 2 1 4 1 2 1 6 1 2 1 2 1