最長迴文子串(longest-palindromic-substring)

題目

給定一個字符串 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#

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章