第九章 動態規劃Part11

haohaoscnblogs發表於2024-08-29

目錄
  • 任務
    • 1143. 最長公共子序列
      • 思路
    • 1035. 不相交的線
      • 思路
    • 53. 最大子陣列和
      • 思路
    • 392. 判斷子序列
      • 思路

任務

1143. 最長公共子序列

給定兩個字串 text1 和 text2,返回這兩個字串的最長 公共子序列 的長度。如果不存在 公共子序列 ,返回 0 。

一個字串的 子序列 是指這樣一個新的字串:它是由原字串在不改變字元的相對順序的情況下刪除某些字元(也可以不刪除任何字元)後組成的新字串。

例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
兩個字串的 公共子序列 是這兩個字串所共同擁有的子序列。

思路

同718. 最長重複子陣列,只是這裡將連續的陣列換成了不連續的子序列,dp[i][j]表示 nums1 以i-1結尾,num2 以j-1結尾的最長公共子序列
相等時同樣用dp[i-1][j-1]+1來擴充長度。
區別是在當前不相等時,用兩陣列前一個索引所表示dp的較大值來保持已有長度。

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        dp = [[0] * (len(text2)+1) for _ in range(len(text1)+1)]
        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
                else:
                    dp[i][j] = max(dp[i][j-1],dp[i-1][j])
                
        return dp[len(text1)][len(text2)]

1035. 不相交的線

在兩條獨立的水平線上按給定的順序寫下 nums1 和 nums2 中的整數。
現在,可以繪製一些連線兩個數字 nums1[i] 和 nums2[j] 的直線,這些直線需要同時滿足:
nums1[i] == nums2[j]
且繪製的直線不與任何其他連線(非水平線)相交。
請注意,連線即使在端點也不能相交:每個數字只能屬於一條連線。
以這種方法繪製線條,並返回可以繪製的最大連線數。

思路

完全是上題LCS的變形,不贅述。

class Solution:
    def maxUncrossedLines(self, nums1: List[int], nums2: List[int]) -> int:
        dp = [[0] * (len(nums2)+1) for _ in range(len(nums1)+1)]
        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][j-1],dp[i-1][j])
                
        return dp[len(nums1)][len(nums2)]

53. 最大子陣列和

給你一個整數陣列 nums ,請你找出一個具有最大和的連續子陣列(子陣列最少包含一個元素),返回其最大和。
子陣列是陣列中的一個連續部分。

思路

dp[i] 是以索引i為結尾的最大和,它為

  • 之前的連續最大和加上自己
  • 自己重新開始記錄

兩者的最大值

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        dp = [0] * len(nums)
        dp[0] = nums[0]
        result = dp[0]
        for i in range(1,len(nums)):
            dp[i] = max(nums[i],dp[i-1]+nums[i])
            result = max(result,dp[i])
        return result

392. 判斷子序列

給定字串 s 和 t ,判斷 s 是否為 t 的子序列。
字串的一個子序列是原始字串刪除一些(也可以不刪除)字元而不改變剩餘字元相對位置形成的新字串。(例如,"ace"是"abcde"的一個子序列,而"aec"不是)。

思路

是LCS的變形,只要兩個字串的最長公共子序列的長度為子序列s的長度,說明s是t的子序列,否則則不是。

class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        dp = [[0] * (len(t)+1) for _ in range(len(s)+1)]
        for i in range(1,len(s) + 1):
            for j in range(1,len(t) + 1):
                if s[i-1] == t[j-1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = max(dp[i][j-1],dp[i-1][j])
        return True if dp[len(s)][len(t)] == len(s) else False

相關文章