【Leetcode5】最長迴文子串

題目描述

在這裏插入圖片描述

解題思路

迴文數:迴文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。(第1個數和第n個數相等,第2個數和第n-1個數相等…)

解法一:暴力法(超時)

python代碼

  • 枚舉所有長度大於等於 2的子串,依次判斷它們是否是迴文;
  • ‘babad’,判斷‘ba’,‘bab’,‘baba’,‘babad’,‘ab’,‘aba’,‘abad’,‘ba’,‘bad’,‘ad’是否符合迴文數
  • 找到最長的迴文子串,例如‘ccc’,最長迴文子串爲‘ccc’,則需加上判斷j-i+1>max_len
class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        if n<2:
            return s
        res = s[0]
        max_len = 1
        for i in range(0,n-1):
            for j in range(i+1,n):
                if j-i+1>max_len and self.valid(s,i,j):
                    max_len = j-i+1
                    res = s[i:j+1]
        return res

    def valid(self,s,m,n):
        while m<n:
            if s[m] != s[n]:
                return False
            else:
                m += 1
                n -=1
        return True

複雜度分析
時間複雜度:O(n^3),這裏n是字符串的長度,枚舉字符串的左邊界、右邊界,然後繼續驗證子串是否是迴文子串,這三種操作都與n相關
空間複雜度:O(1),只使用到常數個臨時變量

解法二:動態規劃

1、如果一個字符串的頭尾兩個字符都不相等,那麼這個字符串一定不是迴文串;
2、如果一個字符串的頭尾兩個字符相等,纔有必要繼續判斷下去。
(1)如果裏面的子串是迴文,整體就是迴文串;
(2)如果裏面的子串不是迴文串,整體就不是迴文串。
瞭解動態規劃:
1、思考狀態
dp[i][j] 表示子串 s[i, j] 是否爲迴文子串。
2、思考狀態轉移方程(核心、難點)
這一步在做分類討論(根據頭尾字符是否相等),根據上面的分析得到:
dp[i][j] = (s[i] == s[j]) and dp[i + 1][j - 1]
分析這個狀態轉移方程:
(1)“動態規劃”事實上是在填一張二維表格,i 和 j 的關係是 i <= j ,因此,只需要填這張表的上半部分;
在這裏插入圖片描述
(2)看到 dp[i + 1][j - 1] 就得考慮邊界情況。
邊界條件是:表達式 [i + 1, j - 1] 不構成區間,即長度嚴格小於 2,即 j - 1 - (i + 1) + 1 < 2 ,整理得 j - i < 3。
這個結論很顯然:當子串 s[i, j] 的長度等於 2 或者等於 3 的時候,我其實只需要判斷一下頭尾兩個字符是否相等就可以直接下結論了。
如果子串 s[i + 1, j - 1] 只有 1 個字符,即去掉兩頭,剩下中間部分只有1個字符,當然是迴文;
如果子串 s[i + 1, j - 1] 爲空串,那麼子串 s[i, j] 一定是迴文子串。
因此,在 s[i] == s[j] 成立和 j - i < 3 的前提下,直接可以下結論,dp[i][j] = true,否則才執行狀態轉移。
3、思考初始化
初始化的時候,單個字符一定是迴文串,因此把對角線先初始化爲 1,即 dp[i][i] = 1
4、思考輸出
只要一得到 dp[i][j] = true,就記錄子串的長度和起始位置,沒有必要截取,因爲截取字符串也要消耗性能,記錄此時的迴文子串的“起始位置”和“迴文長度”即可。
5、思考狀態壓縮
因爲在填表的過程中,只參考了左下方的數值。事實上可以壓縮,但會增加一些判斷語句,增加代碼編寫和理解的難度,丟失可讀性。在這裏不做狀態壓縮。

python代碼

class Solution:
    def longestPalindrome(self, s: str) -> str:
        size = len(s)
        if size < 2:
            return s

        dp = [[False for _ in range(size)] for _ in range(size)]

        max_len = 1
        start = 0

        for i in range(size):
            dp[i][i] = True

        for j in range(1, size):
            for i in range(0, j):
                if s[i] == s[j]:
                    if j - i < 3:
                        dp[i][j] = True
                    else:
                        dp[i][j] = dp[i + 1][j - 1]
                else:
                    dp[i][j] = False

                if dp[i][j]:
                    cur_len = j - i + 1
                    if cur_len > max_len:
                        max_len = cur_len
                        start = i
        return s[start:start + max_len]

複雜度分析
時間複雜度:O(n^2)
空間複雜度:O(n^2)二維 dp 問題,一個狀態得用二維有序數對錶示,因此空間複雜度是 O(n^2)

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