-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path5. 最长回文子串.js
72 lines (71 loc) · 1.91 KB
/
5. 最长回文子串.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
* dp
* @param {string} s
* @return {string}
*/
var longestPalindrome = function (s) {
if (!s || !s.length) return "";
let res = s[0];
const dp = [];
// dp[i][] 依赖 dp[i-1][] --> 干脆反着遍历
for (let i = s.length - 1; i >= 0; i--) {
dp[i] = [];
for (let j = i; j < s.length; j++) {
if (j === i) dp[i][j] = true; // d[i][i] 一个字符当然回文
else if (j === i + 1 && s[i] === s[j]) dp[i][j] = true; //dp[i][i+1]
else if (s[i] === s[j] && dp[i + 1][j - 1]) dp[i][j] = true;
// 有更长的就要更新
if (dp[i][j] && j - i + 1 > res.length) res = s.slice(i, j + 1);
}
}
return res;
};
/**
* manacher
* @param {string} s
* @return {string}
*/
var longestPalindrome = function (s) {
const lens = s.length;
// 预处理字符数组
let str = "#";
for (let i = 0; i < lens; i++) {
str = str + s[i] + "#";
}
// 当前回文子串能到达的右边界和它的中心
let mid = 0,
right = 0;
// 最长的回文子串的中心和长度
let maxLen = 0,
maxLenMid = 0;
// child[i]: 以i为中心的最长回文
const child = [];
// 遍历处理过的字符串,以每个字符中心进行扩展
for (let i = 0; i < str.length; i++) {
// 第i个字符,如果在最右边界的羽翼下,就选择对称字符的回文长度
// 不在右边界内就赋值1
child[i] = i < right ? Math.min(child[2 * mid - i], right - i) : 1;
// 不论怎么样都要试一试暴力扩展
while (
i - child[i] >= 0 &&
i + child[i] < str.length &&
str.charAt(i + child[i]) == str.charAt(i - child[i])
) {
child[i]++;
}
// 更新右边界
if (right < child[i] + i) {
mid = i;
right = child[i] + i;
}
// 是否更新最长回文子串
if (maxLen < child[i]) {
maxLen = child[i];
maxLenMid = i;
}
}
return s.substring(
(maxLenMid + 1 - maxLen) / 2,
(maxLenMid - 1 + maxLen) / 2
);
};