Day 42 | 198.打家劫舍 、213.打家劫舍II、337.打家劫舍III

forrestr發表於2024-07-09

198.打家劫舍

影片講解:https://www.bilibili.com/video/BV1Te411N7SX
https://programmercarl.com/0198.打家劫舍.html
你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。
給定一個代表每個房屋存放金額的非負整數陣列,計算你 不觸動警報裝置的情況下 ,一夜之內能夠偷竊到的最高金額。

思考

第i天能不能偷和i-1和i-2存在關係。
dp[i]:考慮下標i(包括i)以內的房屋,最多可以偷竊的金額為dp[i]。注意考慮不代表一定偷。

class Solution:
    def rob(self, nums: List[int]) -> int:
        if len(nums)==1:
            return nums[0]
        # dp[i] 以i為結尾的序列的最高偷盜額
        dp = [0] *len(nums)
        dp[0] = nums[0]
        dp[1] = max(nums[0],nums[1])

        for i in range(2,len(nums)):
            dp[i] = max(dp[i-1],dp[i-2]+nums[i])
        return dp[len(nums)-1]

213.打家劫舍II

影片講解:https://www.bilibili.com/video/BV1oM411B7xq
https://programmercarl.com/0213.打家劫舍II.html
你是一個專業的小偷,計劃偷竊沿街的房屋,每間房內都藏有一定的現金。這個地方所有的房屋都 圍成一圈 ,這意味著第一個房屋和最後一個房屋是緊挨著的。同時,相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警 。

給定一個代表每個房屋存放金額的非負整數陣列,計算你 在不觸動警報裝置的情況下 ,今晚能夠偷竊到的最高金額。

思考

和上一題的區別是環狀,分別去除首尾,呼叫上一題的函式,然後取最大就行了

class Solution:
    def rob(self, nums: List[int]) -> int:
        def rob_line(nums):
            if len(nums) == 1:
                return nums[0]
            # dp[i] 考慮 nums[0:i]偷的最大值,即以i為結尾的
            dp = [0] * len(nums)
            dp[0] = nums[0]
            dp[1] = max(nums[0],nums[1])
            for i in range(2,len(nums)):
                dp[i] = max(dp[i-1] , dp[i-2]+nums[i])
            return dp[-1]
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return nums[0]
        res1 = rob_line(nums[1:])
        res2 = rob_line(nums[:len(nums)-1])
        return max(res1,res2)

337.打家劫舍III

影片講解:https://www.bilibili.com/video/BV1H24y1Q7sY
https://programmercarl.com/0337.打家劫舍III.html
在上次打劫完一條街道之後和一圈房屋後,小偷又發現了一個新的可行竊的地區。這個地區只有一個入口,我們稱之為“根”。 除了“根”之外,每棟房子有且只有一個“父“房子與之相連。一番偵察之後,聰明的小偷意識到“這個地方的所有房屋的排列類似於一棵二叉樹”。 如果兩個直接相連的房子在同一天晚上被打劫,房屋將自動報警。

計算在不觸動警報的情況下,小偷一晚能夠盜取的最高金額。

思考

這道題目算是樹形dp的入門題目,因為是在樹上進行狀態轉移。遞迴返回值就是dp陣列。

class Solution:
    def rob(self, root: Optional[TreeNode]) -> int:
        # 返回值為當前節點不偷 或 偷的價值
        def traversal(node):
            if node is None:
                return (0,0)
            left = traversal(node.left)
            right = traversal(node.right)
            
            #不偷本節點,可以考慮偷孩子
            dont_rob = max(left[0],left[1]) + max(right[0],right[1])
            #偷本節點,就不能偷孩子
            do_rob = node.val + left[0] + right[0]
            return (dont_rob,do_rob)
        res = traversal(root)
        return max(res)

相關文章