最长回文子串
问题描述
给你一个字符串 s,找到 s 中最长的回文子串。
解题思路
之前做过这道题的类似题:最长回文子序列。
不同的是那道题返回的是最长回文子序列的长度,而这题返回最长回文子串,即返回值为String类型。
虽然返回值不同,但要求是一样的,因此这题我们也可以用动态规划来求解:
对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。我们用dp(i,j) 表示字符串 s 的第i 到 j 个字母组成的串是否为回文串,如果s[i,j]是回文串,则说明s[i]==s[j],并且除去两头后的子串仍是回文串。由此写出状态转移方程:
dp(i,j) == (s[i-1] == s[j+1]) && dp(i+1,j-1)
则最长回文子串就是dp[i][j]为true,且j-i+1为最长的串。
代码实现:
class Solution {
public String longestPalindrome(String s) {
int n = s.length();
boolean[][] dp = new boolean[n][n];
String res = "";
for (int l = 0; l < n; ++l) {//l表示回文串的长度-1
for (int i = 0; i + l < n; ++i) {//i为子串起点
int j = i + l;//j为子串终点
if (l == 0) {//此为 i == j 的情况
dp[i][j] = true;
} else if (l == 1) { //此为回文串只有两个字符的情况,需要两个字符相等才能为真
dp[i][j] = (s.charAt(i) == s.charAt(j));
} else {//推导出的状态转移方程
dp[i][j] = (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]);
}
if (dp[i][j] && l + 1 > res.length()) { //求最长串
res = s.substring(i, i + l + 1);
}
}
}
return res;
}
}
时间复杂度:O(n^2)
空间复杂度:O(n^2)
解法二:
题解还提供了一种思路:遍历字符串的每个字符,逐个以其为回文串的中心进行计算,若中心左右两边相等则继续扩张,若不相等则继续遍历下一个字符。
图解:来源
代码:
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) {
return "";
}
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++) {
int len1 = expandAroundCenter(s, i, i);
int len2 = expandAroundCenter(s, i, i + 1);
int len = Math.max(len1, len2);
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substring(start, end + 1);
}
public int expandAroundCenter(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
--left;
++right;
}
return right - left - 1;
}
}
链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/
来源:力扣(LeetCode)