给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示:
1 <= s.length <= 1000
s 仅由数字和英文字母组成
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-palindromic-substring/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
感谢liweiwei1419的动态规划、中心扩散、Manacher 算法, labuladong的数组双指针直接秒杀七道题目
class Solution {
public String longestPalindrome(String s) {
// return longestPalindromeI(s);
// return longestPalindromeII(s);
return longestPalindromeIII(s);
}
//方法三:动态规划
//定义dp[i][j]表示子串s[i...j]是否为回文串,根据头尾字符是否相等,需要分类讨论:
//dp[i][j] = (s[i] == s[j]) and dp[i + 1][j - 1]
//时间复杂度O(n^2),空间复杂度O(n^2)
private String longestPalindromeIII(String s) {
if (s == null || s.length() < 2) {
return s;
}
int len = s.length();
int maxLen = 1;
int start = 0;
boolean[][] dp = new boolean[len][len];
char[] arr = s.toCharArray();
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
for (int j = 1; j < len; j++) {
for (int i = 0; i < j; i++) {
if (arr[i] != arr[j]) {
dp[i][j] = false;
} else {
if (j - i <= 2) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
}
// 只要 dp[i][j] == true 成立,就表示子串 s[i..j] 是回文,此时记录回文长度和起始位置
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
start = i;
}
}
}
return s.substring(start, start + maxLen);
}
//方法二:双指针,中心扩散法
//回文串可能是奇数,也可能是偶数。如果是奇数,则有一个中心字符,否则有两个中心字符
//定义函数palindrome(s,l,r)表示在s中寻找以s[l]和s[r]为中心的最长回文串
//遍历每一个下标,以这个下标为中心,利用「回文串」中心对称的特点,往两边扩散,看最多能扩散多远。
//时间复杂度O(N^2),空间复杂度O(1)
private String longestPalindromeII(String s) {
if (s == null || s.length() == 0) {
return null;
}
String res = "";
for (int i = 0; i < s.length(); i++) {
//寻找长度为奇数的回文串
String s1 = palindrome(s, i, i);
//寻找长度为偶数的回文串
String s2 = palindrome(s, i, i + 1);
res = s1.length() > res.length() ? s1 : res;
res = s2.length() > res.length() ? s2 : res;
}
return res;
}
private String palindrome(String s, int l, int r) {
while (l >= 0 && r <= s.length() - 1 && s.charAt(l) == s.charAt(r)) {
l--;
r++;
}
return s.substring(l + 1, r);
}
//方法一:暴力解法,枚举所有长度大于等于2的子串,判断是否满足回文串
//时间复杂度O(N^3),空间复杂度O(1)
private String longestPalindromeI(String s) {
if (s == null || s.length() < 2) {
return s;
}
int start = 0, maxLen = 1;
int len = s.length();
char[] arr = s.toCharArray();
for (int i = 0; i < len - 1; i++) {
for (int j = i + 1; j < len; j++) {
if (j - i + 1 > maxLen && validatePalindrome(arr, i, j)) {
//得到更长的回文子串时,更新 当前子串的起始位置 和 子串长度
maxLen = j - i + 1;
start = i;
}
}
}
return s.substring(start, start + maxLen);
}
private boolean validatePalindrome(char[] arr, int i, int j) {
while (i < j) {
if (arr[i] != arr[j]) {
return false;
}
i++;
j--;
}
return true;
}
}