持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
最长回文子串
题目
5. 最长回文子串
难度中等5779收藏分享切换为英文接收动态反馈
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入: s = "babad"
输出: "bab"
解释: "aba" 同样是符合题意的答案。
示例 2:
输入: s = "cbbd"
输出: "bb"
暴力解法
最简单就是暴力解法,即双重循环遍历,依次判断左右元素所组成的字串是否为回文串。
function longestPalindrome(s: string): string {
if (s.length < 2) {
return s;
}
let maxLen = 1;
// maxLength最小为1
let begin = 0;
for (let i = 0; i < s.length - 1; i++) {
for (let j = i + 1; j < s.length; j++) {
//当左右相等进行判断
if (s[i] === s[j]) {
// 此时需要length>1,也就是j-i+1,最小为2.
if (j - i + 1 > maxLen && compare(i, j, s)) {
//当新的回文串长度更长时改变
maxLen = j - i + 1;
//maxLen 应该是左右边界数学相减后加一,slice能够得到正确的结果
begin = i;
//左边界转为起始位置
}
}
}
}
console.log(begin, maxLen + 1);
return s.slice(begin, begin + maxLen);
}
const compare = (i: number, j: number, s: string): boolean => {
while (j - i >= 2) {
if (s[i] === s[j]) {
i++;
j--;
} else {
return false;
}
}
if (s[i] === s[j]) {
return true;
} else return false;
};
const v = longestPalindrome("aacabdkacaa");
console.log(v);
中心扩散法
明显暴力解法是很慢的,做过一些题的小伙伴一定是最先想到中心扩散这种解法,它更快是因为它只需要遍历中心坐标。
我们对每一个中心下标进行判断寻找,找到以它为中心的最长的回文串,然后进行比较赋值。需要注意的是有偶数回文串的情况,也就是当s[i]===s[i+1]时我们是以s[i]和[s+1]为中心来寻找的。我们可以将s[i]中心元素作为两个元素来保证一个函数寻找到最长回文串。
function longestPalindrome(s: string): string {
if (s.length < 2) {
return s;
}
let maxLen = 1;
let begin = 0;
for (let i = 0; i < s.length - 1; i++) {
let re = compare(s, i, i);
if (re[1] - re[0] + 1 > maxLen) {
begin = re[0];
maxLen = re[1] - re[0] + 1;
}
//当两个相等时传入i,i+1;
if (s[i] === s[i + 1]) {
let res = compare(s, i, i + 1);
if (maxLen < res[1] - res[0] + 1) {
maxLen = res[1] - res[0] + 1;
//maxLen依旧用相减加一获取
begin = res[0];
}
}
}
console.log(begin, maxLen);
return s.slice(begin, begin + maxLen);
}
//传入左右元素,若单元素为中心就传入left和right都为这个单元素。
const compare = (s: string, left: number, right: number): number[] => {
while (left - 1 > -1 && right + 1 < s.length) {
if (s[left - 1] == s[right + 1]) {
left--;
right++;
} else {
break;
}
}
// 返回最后一个相等的左右边界
return [left, right];
};
const v = longestPalindrome("ccc");
console.log(v);
空间换时间的动态规划
思想就是对于每个左右边界组成的回文字串,若左右边界相等那么它是否为回文字串取决与它的left++与right--组成的字串是否为回文字串,依次套娃,而长度小于等于三的字串我们是能够很轻易的判断它是ture或false,设置s[i][i]为true。
// 动态规划
function longestPalindrome(s: string): string {
if (s.length < 2) {
return s;
}
let maxLen: number = 1;
let begin = 0;
let twoM: Array<Array<boolean>> = new Array<Array<boolean>>(s.length);
// 创建s.length个长度的数组
for (let i = 0; i < s.length; i++) {
twoM[i] = new Array(s.length);
twoM[i][i] = true;
// 设置对角线为true
}
for (let right = 1; right < s.length; right++) {
for (let left = 0; left < right; left++) {
if (s[left] !== s[right]) {
// 当不等直接判false
twoM[left][right] = false;
} else {
if (right - left < 3) {
// 当距离为小于等于二也就是两个相同或是三个相同也判true
twoM[left][right] = true;
} else {
/*
这是一个注意点,此时我们判它为内部接近的字串的真值
*/
twoM[left][right] = twoM[left + 1][right - 1];
}
}
if (twoM[left][right] && right - left + 1 > maxLen) {
maxLen = right - left + 1;
begin = left;
}
}
}
console.table(twoM);
return s.slice(begin, begin + maxLen);
}
console.log(longestPalindrome("aaabbbb"));
总结
本次文章的难点在于学习动态规划的解法与思想,即用空间减少判断的次数。
结语
本次的文章到这里就结束啦!♥♥♥读者大大们认为写的不错的话点个赞再走哦 ♥♥♥
每天一个知识点,每天都在进步!♥♥