❓ 5. 最长回文子串
难度:中等
给你一个字符串 s
,找到 s
中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
示例 2:
输入:s = “cbbd”
输出:“bb”
提示:
- 1 <= s.length <= 1000
s
仅由数字和英文字母组成
💡思路:
法一:中心点扩展法
首先确定回文串,就是找中心然后想两边扩散看是不是对称的就可以了。
- 一个元素可以作为中心点;
- 两个元素也可以作为中心点。
法二:动态规划
定义 dp
数组,dp[i][j]
表示区间范围 [i,j]
(注意是左闭右闭)的子串是否是回文子串,如果是 dp[i][j]
为 true
,否则为 false
。
要从下到上,从左到右遍历,当 s[i]
与 s[j]
相等时,有如下三种情况:
- 下标
i
与j
相同,同一个字符例如a
,当然是回文子串 - 下标
i
与j
相差为1,例如aa
,也是文子串 - 下标:
i
与j
相差大于1的时候,例如cabac
,此时s[i]
与s[j]
已经相同了,我们看i
到j
区间是不是回文子串就看aba
是不是回文就可以了,那么aba
的区间就是i+1
与j-1
区间,这个区间是不是回文就看dp[i + 1][j - 1]
是否为true
。
🍁代码:(C++、Java)
法一:中心点扩展法
C++
class Solution {
private:int strLen (string s, int l, int r){while(l >= 0 && r < s.size()){if(s[l] == s[r]){l--; r++;}else break;}return r - l - 1;}
public:string longestPalindrome(string s) {int mid = 0, len = 0;int n = s.size();for(int i = 0; i < n; i++){int tmp = strLen(s, i - 1, i + 1);if(i < n - 1 && s[i] == s[i + 1]) {tmp = max(tmp, strLen(s, i - 1, i + 2));} if(tmp > len){mid = i;len = tmp;}}//记录开始点int start = mid - len / 2;if(len % 2 == 0) start += 1;return s.substr(start, len);}
};
Java
class Solution {private int strLen (String s, int l, int r){while(l >= 0 && r < s.length()){if(s.charAt(l) == s.charAt(r)){l--; r++;}else break;}return r - l - 1;}public String longestPalindrome(String s) {int mid = 0, len = 0;int n = s.length();for(int i = 0; i < n; i++){int tmp = strLen(s, i - 1, i + 1);if(i < n - 1 && s.charAt(i) == s.charAt(i + 1)) {tmp = Math.max(tmp, strLen(s, i - 1, i + 2));} if(tmp > len){mid = i;len = tmp;}}//记录开始点int start = mid -len / 2;if(len % 2 == 0) start += 1;return s.substring(start, start + len);}
}
法二:动态规划
C++
class Solution {
public:string longestPalindrome(string s) {vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));int start = 0;int len = 0;for(int i = s.size() - 1; i >= 0; i--){for(int j = i; j < s.size(); j++){if(s[i] == s[j]){if(j - i <= 1 ||dp[i + 1][j - 1]) dp[i][j] = 1;}if(dp[i][j] && j - i + 1 > len){len = j - i + 1;start = i;}}}return s.substr(start, len);}
};
Java
class Solution {public String longestPalindrome(String s) {boolean[][] dp = new boolean[s.length()][s.length()];int start = 0;int len = 0;for(int i = s.length() - 1; i >= 0; i--){for(int j = i; j < s.length(); j++){if(s.charAt(i) == s.charAt(j)){if(j - i <= 1 ||dp[i + 1][j - 1]) dp[i][j] = true;}if(dp[i][j] && j - i + 1 > len){len = j - i + 1;start = i;}}}return s.substring(start, start + len);}
}
🚀 运行结果:
🕔 复杂度分析:
- 时间复杂度: O ( n 2 ) O(n^2) O(n2),其中
n
为字符串的长度。 - 空间复杂度: O ( 1 ) O(1) O(1),法一为 O ( 1 ) O(1) O(1); 法二存储动态规划状态需要 O ( n 2 ) O(n^2) O(n2)空间。
题目来源:力扣。
放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我LeetCode主页 / CSDN—力扣专栏,每日更新!