總結3道關於“迴文串”的leetcode編程題
- 最長迴文子串
- 迴文子串
- 最長迴文子序列
1. 最長迴文子串
題目描述
給定一個字符串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度爲 1000。
示例 1:
輸入: “babad”
輸出: “bab”
注意: “aba” 也是一個有效答案。
示例 2:
輸入: “cbbd”
輸出: “bb”
思路
根據迴文串的特點,採取**“從中間往兩邊擴展”**的方法。
值得注意的是有的迴文串長度是奇數,有的則是偶數
所以你在下面的代碼中會看到下面兩行:
int len1 = expandAroundCenter(s,i,i);
int len2 = expandAroundCenter(s,i,i+1);
它們分別考慮了從當前元素向兩邊擴展以及當前元素和下一個元素作爲中心往兩邊擴展的情況。
Java代碼
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);
}
//得到以left right爲中心軸向兩邊擴展的最長迴文串長
public int expandAroundCenter(String s,int left,int right){
int l = left,r = right;
while(l>=0&&r<s.length()&&s.charAt(l) == s.charAt(r)){
l--;r++;
}
return r-l-1;
}
}
2. 迴文子串
題目描述
給定一個字符串,你的任務是計算這個字符串中有多少個迴文子串。
具有不同開始位置或結束位置的子串,即使是由相同的字符組成,也會被計爲是不同的子串。
示例 1:
輸入: “abc”
輸出: 3
解釋: 三個迴文子串: “a”, “b”, “c”.
示例 2:
輸入: “aaa”
輸出: 6
說明: 6個迴文子串: “a”, “a”, “a”, “aa”, “aa”, “aaa”.
思路
延續上一題“最長迴文子串”的**“從中間往兩邊擴展”**的思路。不同的是,這次是統計迴文串的個數而已。
Java代碼
class Solution {
public int countSubstrings(String s) {
if(s == null||s.length()<1) return 0;
int len = s.length();
int result = 0;//記錄結果
for(int i =0;i<len;i++){
int count1 = expandAroundCount(s,i,i);
int count2 = expandAroundCount(s,i,i+1);
result+=count1;
result+=count2;
}
return result;
}
//得到以left right爲中心軸向兩邊擴展的迴文串的個數
public int expandAroundCount(String s,int left,int right){
int l = left,r=right;
int count = 0;
while(l>=0&&r<s.length() && s.charAt(l) == s.charAt(r)){
l--;
r++;
count++;
}
return count;
}
}
3. 最長迴文自序列
題目描述
給定一個字符串s,找到其中最長的迴文子序列。可以假設s的最大長度爲1000。
示例 1:
輸入:
“bbbab”
輸出:
4
一個可能的最長迴文子序列爲 “bbbb”。
示例 2:
輸入:
“cbbd”
輸出:
2
一個可能的最長迴文子序列爲 “bb”。
思路
注意子序列和字串的區別:字串是連續的,而子序列不要求連續
由於自序列的不連續性,意味着這個題不能像前兩題那樣採用“中心擴展法”了。
怎麼辦呢?
類似動態規劃吧,用一個二維數組存放其子串 j 到 i 的最長迴文子序列:dp[j][i]表示字串s[j:i+1]的最長迴文子序列
通過字串的慢慢擴展,直到遍歷整個串,統計出最長的長度。
Java代碼
class Solution {
public int longestPalindromeSubseq(String s) {
if(s == null || s.length()<1) return 0;
int len = s.length();
//dp[j][i]表示字串s[j:i+1]的最長迴文子序列
int[][] dp = new int[len][len];
int res = 0;
for(int i =0;i<len;i++){
for(int j=i;j>=0;j--){
if(i-j<2){
dp[j][i] = s.charAt(j) == s.charAt(i) ? i-j+1 : i-j;
}else{
if(s.charAt(j) == s.charAt(i)){
dp[j][i] = dp[j+1][i-1]+2;
}else{
dp[j][i] = Math.max(dp[j+1][i],dp[j][i-1]);
}
}
res = Math.max(res, dp[j][i]);
}
}
return res;
}
}