5. 最长回文子串
给定一个字符串 s
,找到 s
中最长的回文子串。你可以假设 s
的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
class Solution {
public String longestPalindrome(String s) {
String res = new String();
int max = 0;
for(int i = 0;i<s.length();i++){
//substring(i,j); [i,j) 左闭右开区间
for(int j = i+1; j<=s.length();j++){
//分割子字符串
String temp = s.substring(i,j);
//判断是否为回文子串 是赋值给res 并保存最长长度
if(isPalidrome(temp)&&temp.length()>max){
res = temp;
max = Math.max(res.length(),max);
}
}
}
return res;
}
//判断是否为回文子串
public static boolean isPalidrome(String arr){
int len = arr.length();
for(int i = 0 ;i<len/2;i++){
//判断得到的字符串是否回文子串 不是 返回false 0与 length-1比较 1与length-1-1相比 以此类推
if(arr.charAt(i)!=arr.charAt(len-1-i)){
return false;
}
}
return true;
}
}
-
动态规划
对于一个子串而言,如果它是回文串,并且长度大于 22,那么将它首尾的两个字母去除之后,它仍然是个回文串。例如对于字符串“ababa”,如果我们已经知道“bab” 是回文串,那么 “ababa” 一定是回文串,这是因为它的首尾两个字母都是 “a”。
根据这样的思路,我们就可以用动态规划的方法解决本题。我们用 P(i,j)表示字符串 s 的第 i 到 j个字母组成的串(下文表示成 s[i:j])是否为回文串:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LlmsZIHY-1607434207089)(C:\Users\ADMINI~1\AppData\Local\Temp\1607429143204.png)]
这里的「其它情况」包含两种可能性:
-
s[i, j]s[i,j] 本身不是一个回文串;
-
i > ji>j,此时 s[i, j]s[i,j] 本身不合法。
-
那么我们就可以写出动态规划的状态转移方程:
P
(
i
,
j
)
=
P
(
i
+
1
,
j
−
1
)
∧
(
S
i
=
=
S
j
)
P(i, j) = P(i+1, j-1)∧(Si ==Sj)
P(i,j)=P(i+1,j−1)∧(Si==Sj)
也就是说,只有 s[i+1:j-1]是回文串,并且 s 的第 i和 j个字母相同时,s[i:j]才会是回文串。
对于特殊的情况
-
当子串长度为1时,P(i,j) = true
-
当子串长度为2时,
P ( i , i + 1 ) = ( S i = = S i + 1 ) P(i,i+1) = (Si == Si+1) P(i,i+1)=(Si==Si+1)
图形说明
class Solution {
//动态规划
public String longestPalindrome(String s) {
int n = s.length();
String res="";
boolean[][] dp = new boolean[n][n];
for(int l=0;l<n;l++){
//循环终止条件:i+l<n 循环只在对角线的斜上方的数据
for(int i = 0;i+l<n;i++){
//第一轮:dp[0][0] dp[1][1] dp[2][2] i与j相等 因为l=0
//第二轮:dp[0][1] dp[1][2] dp[2][3] i与j差一位 因为l=1
//第二轮:dp[0][2] dp[1][3] dp[2][4] i与j差两位 因为l=2 ......
int j = i+l;
if(l == 0){
//单个字符的情况
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;
}
}
class Solution {
//动态规划
public String longestPalindrome(String s) {
int n = s.length();
if(n<2) return s;
String res="";
int maxLength=0;
for(int i=0;i<n-1;i++){
String oddSearch = centerSpread(i,i,s); //奇数个数情况
String evenSearch = centerSpread(i,i+1,s); //偶数个数情况
String tempRes = oddSearch.length()>evenSearch.length()?oddSearch:evenSearch;
if(tempRes.length()>maxLength){
maxLength = tempRes.length();
res = tempRes;
}
}
return res;
}
public static String centerSpread(int left,int right,String s){
int i = left;
int j = right;
while(i>=0 &&j<s.length()){
if(s.charAt(i) == s.charAt(j)){
//向外散开
i--;
j++;
}else{
break;
}
}
//因为最后一个i是不满足回文串的情况 所以要+1
return s.substring(i+1,j);
}
}