程式碼隨想錄演算法訓練營day46| 647. 迴文子串 516.最長迴文子序列

Tristan241001發表於2024-11-14

學習資料:https://programmercarl.com/0647.迴文子串.html#演算法公開課

動態規劃最後一部分:迴文字串
子串是從原字串中連續擷取的;子序列可以是從原字串中不連續提取出元素構成的

學習記錄:
647.迴文子串(難構造dp陣列,dp陣列是從原字串擷取[i,j]範圍的片段是否是迴文字串,布林變數;這樣構造才能推出遞推公式,就是當前值是二維陣列中它的左下角的值來推匯出來的)

點選檢視程式碼
class Solution(object):
    def countSubstrings(self, s):
        """
        :type s: str
        :rtype: int
        """
        # 解法一:動態規劃
        # dp[i][j]代表[i,j]對應的s的片段是否為迴文子串,值為false/true
        # 若首尾相等s[i]==s[j],則有三種情況s='a'則i==j;若s='aa',則i+1==j;若s='abxxxa',則j-i>1

        # 構造dp二維陣列
        dp = [[False]*len(s) for _ in range(len(s))]
        # 初始化,略過

        # 實時更新迴文子串個數
        result = 0

        # 開始遍歷(從下到上,從左到右)
        # 難點:這裡i倒序遍歷是因為遞推公式的第二種情況,要先知道dp[i+1][j-1]再求dp[i][j],相當於從左下角推導至當前值
        for i in range(len(s)-1, -1, -1):  # 第二個-1代表截至0
            for j in range(i, len(s)):     # !!!!!!! j也就是橫座標從i開始增加,因為dp[i][j]是從i到j !!!!!
                if s[i] == s[j]:
                    if j-i<=1:     # 合併情況一、二(必然是迴文子串)
                        result += 1
                        dp[i][j] = True
                    elif dp[i+1][j-1]:    # 情況三(此情況下,如果中間段是迴文子串,則向外擴寬1後認為迴文子串)
                        result += 1
                        dp[i][j] = True
        return result
                       

        # 解法二:雙指標(略)
        

516.最長迴文子序列(可以不連續,所有dp陣列代表原字串在[i,j]範圍內的片段中迴文子序列的最長長度;這樣構造是為了更好的得到遞推公式)

點選檢視程式碼
class Solution(object):
    def longestPalindromeSubseq(self, s):
        """
        :type s: str
        :rtype: int
        """
        # 動態規劃,這道題迴文子序列是可以從s中不連續提取元素來構成的
        # dp[i][j]代表[i,j]範圍內迴文子序列的最長長度
        # 構造二維dp陣列
        dp = [[0]*len(s) for _ in range(len(s))]
        # 初始化,因為[i,j]範圍內找回文子序列肯定是向中間靠攏的,那最中間是遍歷不到的,需要初始化
        for i in range(len(s)):
            dp[i][i] = 1    # 一個字母也是一個迴文子序列,長度為1
        # 開始遍歷,同理因為由左下角推導本位置,i從下到上,j從i+1開始然後從左到右遍歷
        for i in range(len(s)-1, -1, -1):
            for j in range(i+1, len(s)):  # 前面初始化過[i][i]的情況,這裡從i+1開始
                # 判斷邏輯
                if s[i] == s[j]:
                    dp[i][j] = dp[i+1][j-1] + 2    # 在中間片段的迴文子序列基礎上加i和j對應值,就是+2
                else:
                    dp[i][j] = max(dp[i+1][j], dp[i][j-1])    # 相當於新增任意一邊的元素後,迴文子序列不變

        return dp[0][len(s)-1]  # 返回從0到末尾的迴文子序列的最長長度

        

PS:動態規劃終於學完了,好充實的題量,前面揹包那些很多沒懂,後面股票、子序列問題能聽懂,但是想不到要討論的那麼多情況。還需多刷呀。
今天天氣陰,吃了好吃的粵菜早茶,貨真價值味道也好,就是給我膩的嘞,還是淺嘗比較適合我,趕緊來了個豌雜麵緩過來了。

相關文章