打家劫舍(動態規劃)

打家劫舍(Ⅰ)
你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。
給定一個代表每個房屋存放金額的非負整數數組,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。

考慮所有可能的搶劫方案過於困難。一個自然而然的想法是首先從最簡單的情況開始。記:

f(k) = 從前 k 個房屋中能搶劫到的最大數額,A_iA i = 第 i 個房屋的錢數。

首先看 n = 1 的情況,顯然 f(1) = A_1A 1 。

再看 n = 2,f(2) = max(A_1A 1 , A_2A 2 )。

對於 n = 3,有兩個選項:

搶第三個房子,將數額與第一個房子相加。

不搶第三個房子,保持現有最大數額。

顯然,你想選擇數額更大的選項。於是,可以總結出公式:

f(k) = max(f(k – 2) + A_kA k , f(k – 1))

我們選擇 f(–1) = f(0) = 0 爲初始情況,這將極大地簡化代碼。

答案爲 f(n)。可以用一個數組來存儲並計算結果。不過由於每一步你只需要前兩個最大值,兩個變量就足夠用了。

class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 0:
            return 0
        pre = cur = 0
        for c in nums:
            pre, cur = cur, max(pre + c, cur)
        return cur

打家劫舍(Ⅱ)
你是一個專業的小偷,計劃偷竊沿街的房屋,每間房內都藏有一定的現金。這個地方所有的房屋都圍成一圈,這意味着第一個房屋和最後一個房屋是緊挨着的。同時,相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。

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

環狀排列意味着第一個房子和最後一個房子中只能選擇一個偷竊,因此可以把此環狀排列房間問題約化爲兩個單排排列房間子問題:
在不偷竊第一個房子的情況下(即 nums[1:]nums[1:]),最大金額是 p_1p1;在不偷竊最後一個房子的情況下(即 nums[:n-1]nums[:n−1]),最大金額是 p_2p 2 。綜合偷竊最大金額: 爲以上兩種情況的較大值,即 max(p1,p2)max(p1,p2) 。

class Solution:
    def rob(self, nums: [int]) -> int:
        def my_rob(nums):
            cur, pre = 0, 0
            for num in nums:
                cur, pre = max(pre + num, cur), cur
            return cur
        return max(my_rob(nums[:-1]),my_rob(nums[1:])) if len(nums) != 1 else nums[0]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章