1 题目及相关定义介绍
1.1 题目介绍
给你一个字符串 s
,找到 s
中最长的回文子串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示: 1 <= s.length <= 1000 s 仅由数字和英文字母(大写和/或小写)组成
题目来源:leetcode-cn.com/problems/lo…
2.2 相关定义
子串
串中任意个连续的字符组成的子序列称为该串的子串;
与之对应的还有一个概念,就是子序列,子序列就是在原来序列中找出一部分组成的序列;
区别
对于一个字符串而言:比如:helloStoney;
子串是在字符串中,取出一块(连续的),如hello, Stoney;
子序列指的是从字符串中,顺序取出字符,但是可以不连续,如:hlo, hlSn等
2 暴力解法
解法介绍
- 列举出所有的子串,时间复杂度:O(n^2)
- 检查每一个子串是否为回文子串,每个子串的时间复杂度:O(n)
- 总时间复杂度O(n^3), 空间复杂度O(1);
3 动态规划解法
3.1 解法详解
动态规划解法是基于暴力解法的优化,优化的部分:判断每个串是否为回文串;
时间复杂度:O(n^2);
空间复杂度:O(n^2);
空间复杂度可以优化至O(n);
假设字符串("abbaba")为s,它的长度为n;
定义dp数组,dp[i][j]:表示s[i][j]是否为回文子串,存储值为0, 1;
分以下两种情况求出dp[i][j]的值:
1,如果s[i, j]的长度(j - i + 1) <= 2时;
- 如果s[i] === s[j],那么s[i][j]是回文串,所以dp[i][j] = s[i] === s[j];
2,如果s[i, j]的长度(j - i + 1) > 2时;
- 如果s[i + 1, j - 1]是回文串,并且s[i] === s[j],那么s[i, j]是回文串;
- 所以dp[i][j] = dp[i + 1, j - 1] && s[i] === s[j];
3.2 代码实现
var longestPalindrome = function(s) {
let length = s.length;
if(s == null) return null;
if(length <= 1) {
return s;
}
let dp = Array.from(new Array(length), () => new Array(length).fill(0));
let maxlen = 1;
let begin = 0;
for (let i = length - 1; i >= 0; i--) {
for (let j = i; j < length; j++) {
let len = j - i + 1;
dp[i][j] = (s[i] === s[j]) && (len <= 2 || dp[i + 1][j - 1]);
if(dp[i][j] && len > maxlen) {
maxlen = len;
begin = i;
}
}
}
return s.substring(begin, begin + maxlen)
};
4 扩散中新解法
4.1 解法介绍
如果所示:有两种扩散方式;
假设字符串("abbaba")的长度为n,那么一共有n + (n - 1) = 2n - 1个扩展中心;
时间复杂度:O(n^2)
空间复杂度:O(1);
4.2 代码实现
var longestPalindrome = function(s) {
if (s === null) return null;
let length = s.length;
if(length <= 1) return s;
let maxLen = 1;
let begin = 0;
for (let i = length - 2; i >= 1; i--) {
// 以字符中心向左右扩散
let len1 = palindromeLength(s, i - 1, i + 1);
// 以字符右边的间隙为中心向左右扩散
let len2 = palindromeLength(s, i, i + 1);
len1 = Math.max(len1, len2);
if(len1 > maxLen) {
maxLen = len1;
begin = i - ((maxLen - 1) >> 1);
}
}
// 以0号字符右边的间隙为中心的最长回文子串长度是2
if(s[0] === s[1] && maxLen < 2) {
begin = 0;
maxLen = 2;
}
return s.substring(begin, maxLen + begin)
};
// 从l开始向左扩散,从r开始向右扩散,获得最长回文子串的长度
function palindromeLength(s, l, r) {
while(l >= 0 && r < s.length && s[l] === s[r]) {
l--;
r++;
}
return r - l - 1;
}
5 扩散中心解法优化
5.1 解法介绍
算法的核心思想:由连续的相同的字符组成的子串作为扩散中心;
所以,"babbbabaa"的扩散中心有:"b", "a", "bbb", "a", "b", "aa";
核心思想
找到左边第一个不等于s[i]的字符,记为位置r, i左边位置记为l;
r作为下一次的i;
由l开始向左,r开始向右扩展,找到最长的回文子串;
5.2 代码实现
var longestPalindrome = function(s) {
if (s === null) return null;
let length = s.length;
if(length <= 1) return s;
let maxLen = 1;
let begin = 0;
let i = 0;
while(i < length) {
let l = i - 1;
// 找到右边第一个不等于s[i]的位置
let r = i;
while(++r < length && s[r] === s[i]);
// r会成为新的i
i = r;
// 从l向左,r向右扩散
while(l >= 0 && r < length && s[l] === s[r]) {
l--;
r++;
}
// 扩展结束后,cs[l + 1, r)就是刚才找到的最大回文子串
// ++l后, l就是刚才找到的最大回文子串的开始索引
let len = r - ++l;
if(len > maxLen) {
maxLen = len;
begin = l;
}
}
return s.substring(begin, begin + maxLen)
};
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!