5. 最长回文子串
链接:https://leetcode-cn.com/problems/longest-palindromic-substring/
题目描述见链接内容。
解法1:动态规划
(1)第一步:定义数组元素的含义
dp[i][j]
定义为从从i
开始,到j
结束的字符串是不是一个回文串,是的话填充true
(2)第二步:找出数组元素之间的关系式
如果一个子串是回文串,那么去掉首尾字符,剩下的子串也一定是回文串,那么就可以得到状态转义方程:
dp[i][j] = dp[i + 1][j - 1] && (s[i] === s[j])
要注意的是转移方向,由于去掉的首字符和尾字符,相当于向内部收缩,所以i
需要+1
,而j
需要-1
(3)第三步:找出初始值
需要找出边界条件,当字符串长度为1
时,那么它一定是个回文串,当字符串长度为2
时,如果首尾两个字符串相等那么它就是回文串,不需要考虑数dp[i + 1][j - 1]
的情况
(4)具体实现
在实现的时候,我一开始按照常规的对i
和j
进行内外双层遍历,但是发现,在遍历到j
比较大时,较小的值并没有计算出来,需要将外层遍历改为遍历子串的长度
var longestPalindrome = function (s) {
const length = s.length;
if (length < 2) {
return s;
}
let result = s[0];
const dp = [];
// 遍历子串长度
for (let L = 2; L <= length; L++) {
// 遍历起始位置
for (let i = 0; i < length; i++) {
// 初始化
if (!Array.isArray(dp[i])) {
dp[i] = [];
}
// j - i + 1 = L
let j = L + i - 1;
// 右边界越界了,退出循环
if (j >= length) {
break;
}
// 如果首尾字符串不等,那么一定不是回文串
if (s[i] !== s[j]) {
dp[i][j] = false;
} else {
// 首尾字符串相等,如果长度是1或者2,那么一定是回文串
if (j - i <= 2) {
dp[i][j] = true;
} else {
// 如果长度大于2,就需要考虑去掉首尾后的情况了
dp[i][j] = dp[i + 1][j - 1];
}
}
// 如果是一个回文串,那么看一下与现在回文串谁更长
if (dp[i][j] && j - i + 1 > result.length) {
result = s.slice(i, j + 1);
}
}
}
return result;
};
- 时间复杂度:
${O(N^2)}$
- 空间复杂度:
${O(N^2)}$
- 执行用时:2012ms, 在所有JavaScript提交中击败了15.210%的用户,内存消耗:66.2MB,在所有JavaScript提交中击败了22.03%的用户
解法2:中心扩展法
所有的回文串都是中心对称的,所以枚举所有的回文中心,并尝试向两侧扩展,直到无法扩展,此时的回文串长度就是次回文中心下的最长回文串长度。
在遍历时要注意,回文串的长度可以是奇数(一个元素为中心)也可以是偶数(两个元素为中心),所以要处理两次
var longestPalindrome = function (s) {
const length = s.length;
if (length === 0 || length === 1) {
return s;
}
let result = s[0];
for (let i = 0; i < length; i++) {
// 一个元素为中心的回文串
const s1 = expandFromCenter(s, i, i),
// 两个元素为中心的回文串
s2 = expandFromCenter(s, i, i + 1),
maxS = s1.length > s2.length ? s1 : s2;
if (maxS.length > result.length) {
result = maxS;
}
}
return result;
};
function expandFromCenter(s, l, r) {
const len = s.length;
while (l >= 0 && r < len && s[l] === s[r]) {
l--;
r++;
}
// 正常slice的参数应该是(l, r + 1),但是由于最后一次l--和r++是多余的,所以l应该+1,而r应该-1
return s.slice(l + 1, r);
}
- 时间复杂度:
${O(N^2)}$
- 空间复杂度:
${O(1)}$
- 执行用时:100ms, 在所有JavaScript提交中击败了97.61%的用户,内存消耗:40.6MB,在所有JavaScript提交中击败了65.64%的用户