题目
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
代码
解法 1: 暴力破解
暴力求解,列举所有的子串,判断是否为回文串,保存最长的回文串。
// 暴力解法
public String longestPalindrome(String s) {
String ans = "";
int max = 0;
int len = s.length();
for (int i = 0; i < len; i++)
for (int j = i + 1; j <= len; j++) {
String test = s.substring(i, j);
if (isPalindromic(test) && test.length() > max) {
ans = s.substring(i, j);
max = Math.max(max, ans.length());
}
}
return ans;
}
public boolean isPalindromic(String s) {
int len = s.length();
for (int i = 0; i < len / 2; i++) {
if (s.charAt(i) != s.charAt(len - i - 1)) {
return false;
}
}
return true;
}
解法2 : 动态规划
方法一中,存在大量的重复计算工作,例如当 s=“abcba” 时, 对于子串 “bcb” 和 子串 “abcba”, 分别进行了2次完整的计算,来检测该子串是否是回文串。
很明显的是,对于 s=“abcba” , 在已知 "bcb"是回文串的情况下,要判断 "bcb"是否是回文串的话,只需要判断两边的*位置的字符是否相等即可。 我们定义 P(i,j) 表示 s[i,j]是否是回文串,若s[i,j]是回文串,则P(i,j)=true,否则为false. 则有下面的递推公式成立:
P[i,j] = p(i+1,j-1) && ( s[i]==s[j] )
对于上面公式有2个特殊情况,当子串长度为1或2时,上面公式不成立。我们单独分析这两种情况:
若子串长度为1,即 j==i, 则 P[i,j] = P[i,i] = true;
若子串长为2,即j==i+1, 则 P[i,j] = P[i,i+1] = ( s[i]==s[i+1] )
在实际执行时,我们先求所有长度为1的子串的P值,再求所有长度为2的子串的P值,之后再求长度3的,以此类推,一直到长度为s.Length的。例如 s=“abcba” ,则P的值 类似下图:
代码
public String longestPalindrome(String s) {
if (s == null || s.length() < 2) {
return s;
}
int strLen = s.length();
int start = 0; // 最长回文串的起点
int end = 0; // 最长回文串的终点
int maxLen = 1; // 最长回文串的长度
boolean[][] dp = new boolean[strLen][strLen];
for (int r = 1; r < strLen; r++) {//思考,为什么要从1开始
for (int l = 0; l < r; l++) {
if ((r - l <= 2 || dp[l + 1][r - 1]) && s.charAt(l) == s.charAt(r)) {
dp[l][r] = true;
if (r - l + 1 > maxLen) {//思考,为什么要加 1
maxLen = r - l + 1;
start = l;
end = r;
}
}
}
}
return s.substring(start, end + 1);//思考,为什么要加 1
}
思考,为什么要从1开始?因为是中心扩散法,两边没有值怎么扩散。
思考,为什么要加1?因为数组[1,2,3]的下标为0,1,2。但是长度为3。
思考,为什么要加 1?因为substring方法返回的是beginIndex到endIndex-1的字符。
注意
DP数组初始化时,当right-1== left+1
的时候就是两边界相等的时候,移项,得right-left==2
,所有有r-l<=2
的时候就是区间不存在的情况,这个时候dp[l][r]是没有意义的。
若子串长度为1,dp[i,i] = true
;
若子串长为2,则 dp[i,j] = dp[i,i+1] = ( s[i]==s[i+1] )
子串长度为1,都是True
,子串长度为2时,要判断。
资料
windliang资料
LeetCode 5. Longest Palindromic Substring 最长回文子串 C#