1. 程式人生 > 實用技巧 >動態規劃系列之五打家劫舍

動態規劃系列之五打家劫舍

題目

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

示例 1:

輸入:[1,2,3,1]
輸出:4
解釋:偷竊 1 號房屋 (金額 = 1) ,然後偷竊 3 號房屋 (金額 = 3)。
    偷竊到的最高金額 = 1 + 3 = 4 。
示例 2:

輸入:[2,7,9,3,1]
輸出:12
解釋:偷竊 1 號房屋 (金額 = 2), 偷竊 3 號房屋 (金額 = 9),接著偷竊 5 號房屋 (金額 = 1)。
    偷竊到的最高金額 = 2 + 9 + 1 = 12 。

解題思路

本題本質上還是求一個子陣列累計和最大值,但與前面的題目略有不同。前面說過能夠代表動態規劃的兩個題目:最大子序和是求連續的子陣列的累積和;梅花樁是最長上升子陣列,是求不連續的子陣列的上升陣列。而本題是一個新增的型別,求子陣列,要求間隔一個取一個。
那麼解題思路和前面的類似,還是構建一個dp陣列,不斷填充dp陣列的值,最後一位就是所求。

建立數學模型

構建dp陣列,以dp[i]代表第i個房間能夠偷竊到的最高金額

狀態轉移方程

狀態轉移方程應該這麼思考:以[2,7,9,3,1]為例,房間一共有5個。
求解第5個房間,要知道知道第4個房間,求解第4個房間要知道第3個房間,一直到第一個房間。已知第一個房間的偷竊最大值是2。
第二個房間最大值:拿當前房間的,或者不拿當前房間的,比較哪一個大。max(2,7) = 7,所以第二個房間最大值為7
第三個房間最大值:拿當前房間的和第一個房間的,或者不拿值為第二房間最大值。max(2+9,7) = 11,所以第三個房間的最大值11
第四個房間最大值:拿當前房間和第二個房間的,或者不拿值為第三個房間最大值。max(7+3,11) = 11,所以第四個房間的最大值11
第五個房間最大值:拿當前房間和第三個房間的,或者不拿值為第四個房間最大值。max(11+1,11) = 12,所以第五個房間的最大值為12

根據這個規律,可以發現就是比較當前房間的值+前兩個房間的最大值和前一個房間的最大值,即:arr[i] + dp[i-2]dp[i-1]

邊界值

邊界值很明顯,第一個房間的最大值就是arr[0],第二個房間的最大值要比較是max(arr[0], arr[1])。即哪一個大就取哪一個。

程式碼實現


def rob(nums):

    if not nums:
        return 0
    
    if len(nums) == 1:
        return nums[0]
    
    length = len(nums)
    dp = [0] * length

    dp[0] = nums[0]
    dp[1] = max(nums[0],nums[1])

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

arr = [2,7,9,3,1]
value = rob(arr)
print(value)
------------------------------------------------
12