題目描述
最長迴文子串
給定一個字符串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度爲 1000。
示例 1:
輸入: “babad”
輸出: “bab”
注意: “aba” 也是一個有效答案。
示例 2:
輸入: “cbbd”
輸出: “bb”
解題思路
看到這道題的時候,第一眼能想到的方法就是暴力破解,枚舉每個子串,看它是不是迴文子串,並且記錄最長的迴文子串。它的時間複雜度爲O(N^3),空間複雜度爲O(N),這裏N指的是數組的長度。
時間複雜度爲O(N^3)的原因是使用兩層for循環找到所有的子串,然後再使用一層for循環判斷該子串是否爲迴文子串。這裏我們不討論它的實現。
接下來我們討論如何使用動態規劃解決這個問題。
動態規劃解題模板
動態規劃解題是有章可循的,我們可以將其分爲以下五步:
(1)確定dp數組元素的含義
(2)確定狀態轉移方程
(3)確定初始值
(4)根據初始值和狀態轉移方程確定dp數組元素的值
(5)考慮空間壓縮
我們直接結合代碼來分析:
第一步:確定dp數組元素的含義
- 對於最長迴文子串我們可以定義數組dp[i][j]表示區間[i,j]是否爲迴文子串。
第二步:確定狀態轉移方程
- 如果 s[i]!=s[j] ,將dp[i][j]置爲false;
- 如果 s[i]==s[j],並且dp[i+1][j-1]==true,我們則將dp[i][j]置爲true;
- 考慮特殊情況如 “aa”, “aba” ,當s[i]==s[j]的時候可以直接將其置爲true,因此可以得到 s[i]==s[j]&&j-i<3時 dp[i][j]=true;
第三步:確定初始值
- 每一個元素都爲一個迴文子串,因此對於 0<i<s.length(),dp[i][i]=true;
第四步:根據初始值和狀態方程確定數組元素的值
- 這裏使用兩層for循環將確定每個子串是否爲迴文。
第五步:考慮空間壓縮
代碼實現
class Solution {
public String longestPalindrome(String s) {
//判非
if(s==null||s.length()<=1){
return s;
}
int len=s.length();
char[] arr=s.toCharArray();
//確定數組元素含義
boolean dp[][]=new boolean[len][len];
//初始化
for(int i=0;i<len;i++){
dp[i][i]=true;
}
int maxLen=1;//記錄最大回文子串的長度
int start=0;//記錄最大回文串的起始座標
//根據初始值和狀態方程確定數組元素的值
for(int j=1;j<len;j++){
for(int i=0;i<j;i++){
if(arr[i]==arr[j]){
if(j-i<3||dp[i+1][j-1]){
dp[i][j]=true;
int l=j-i+1;
if(maxLen<l){//判斷長度
start=i;
maxLen=l;
}
}
}else{
dp[i][j]=false;
}
}
}
return s.substring(start,start+maxLen);
}
}