程式碼隨想錄演算法訓練營day44| 1143.最長公共子序列 1035.不相交的線 53. 最大子序和 392.判斷子序列

Tristan241001發表於2024-11-12

學習資料:https://programmercarl.com/1143.最長公共子序列.html#演算法公開課

動態規劃系列之子序列
其實有些用貪心也可解

學習記錄:
1143.最長公共子序列(dp[i][j]是代表的i-1和j-1為止的兩個片段的最長公共子序列,原因是為了更好的初始化;比如當dp[0][0]代表的到-1和-1的兩個片段,那肯定不存在,所以兩個片段無交集,值為0,否則還得仔細考慮兩者交集)

點選檢視程式碼
class Solution(object):
    def longestCommonSubsequence(self, text1, text2):
        """
        :type text1: str
        :type text2: str
        :rtype: int
        """
        # dp[i][j]代表num1中到i-1和nums2中到j-1為止的兩段的最長公共子序列長度
        # 構造二維dp陣列
        dp = [[0]*(len(text2)+1) for _ in range((len(text1)+1))]
        # 初始化也是0,跳過

        # 開始遍歷
        for i in range(1, len(text1)+1):
            for j in range(1, len(text2)+1):
                if text1[i-1] == text2[j-1]:    
                    dp[i][j] = dp[i-1][j-1] + 1   # 由左上角的值加1
                else:
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])       # 由左邊和上邊的值確定
        return dp[len(text1)][len(text2)]  # 右下角的值
        

1035.不相交的線(與最長公共子序列的解法一致)

點選檢視程式碼
class Solution(object):
    def maxUncrossedLines(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: int
        """
        # 與最長公共子序列解法一致
        # dp[i][j]是nums1的i及之前和nums2的j及之前的最長公共子序列
        dp = [[0]*(len(nums2)+1) for _ in range(len(nums1)+1)]
        # 初始化也是把左邊和上邊設定為0

        # 開始遍歷
        for i in range(1, len(nums1)+1):
            for j in range(1, len(nums2)+1):
                if nums1[i-1] == nums2[j-1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])
        return dp[len(nums1)][len(nums2)]

53.最大子序和(當涉及連續條件時,就用一維陣列,比較i-1與i;有動態規劃和貪心兩種解法,基本思想一樣,當前面和為負(前面的和+nums[i]<nums[i])就捨棄,才能避免拖累下一個數;一維dp陣列,dp[i]代表到i為止的連續子序列的最大和;最大和可能在遍歷的中間位置,記得隨時更新記錄)

點選檢視程式碼
class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 動態規劃解法
        # dp[i]代表nums以i為結尾時的連續子陣列的最大和
        dp = [[0] for _ in range(len(nums))]
        # 初始化
        dp[0] = nums[0]
        # 更新最大和
        result = nums[0]
        # 開始遍歷
        for i in range(1, len(nums)):
            # 若前幾個數的和為整數,那現在的和就加上nums[i];若和為負數就捨棄,只保留nums[i]
            dp[i] = max(dp[i-1]+nums[i], nums[i])
            result = max(dp[i], result)
        return result

        # # 解法一:貪心演算法嗎?怎麼不做記錄
        # if not nums:
        #     return 0
        # dp = [nums[0]]
        # res=dp[0]
        # for i in range(1, len(nums)):
        #     dp.append(max(dp[i-1]+nums[i], nums[i]))
        #     if dp[-1]>res:
        #         res=dp[-1]
        # return res

392.判斷子序列(這道題也與最大公共子序列解法一致,具體思路:當兩者的最大公共子序列等於前者長度時,說明前者是後者的子序列)

點選檢視程式碼
class Solution(object):
    def isSubsequence(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: bool
        """
        # 此題解法基於最長公共子序列,如果兩者的最長公共子序列的長度正好等於s的長度,那就說明s就是t的子序列
        # dp[i][j]代表字串s的前i-1段和字串t的前j-1段的最長公共子序列長度,這裡用i-1,j-1是為了後面初始化
        # 構建二維dp陣列
        dp = [[0]*(len(t)+1) for _ in range(len(s)+1)]
        # 初始化
        # 就是第一行和第一列的值都能為零,因為比如dp[0][j]是s的前-1段和t的前j-1段,-1段肯定不存在所以兩者公共為0;
        # 但是如果前面dp[i][j]設定為前i段和前j段,這裡第一行第一列就可能非零了,那很麻煩的。

        # 開始遍歷
        for i in range(1, len(s)+1):
            for j in range(1, len(t)+1):
                # 由於dp[i-1][j-1]是到i-2和到j-2的公共子序列長度,那如果i-1和j-1處正好相等,那公共子序列長度就再加1
                if s[i-1] == t[j-1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = dp[i][j-1]
        if dp[len(s)][len(t)] == len(s):   # 如果公共子序列長度等於s字串長度,說明s是t的子序列
            return True
        else:
            return False

        

PS:今天還是子序列問題,比昨天聽的更明白了。
下小雨就像吃點熱乎的,今天吃了好吃的排骨米線,辣辣的火雞面、芝士牛肉石鍋、章魚小丸子,很滿足,很撐
2024.11.11 19:48左右 樊某駕車闖入珠海市體育中心,造成35人死亡、43人受傷。

相關文章