1. 程式人生 > >Leetcode初級演算法 打家劫舍(動態規劃)(Python實現)

Leetcode初級演算法 打家劫舍(動態規劃)(Python實現)

問題描述:

演算法思想:

該問題的內在邏輯結構依然是動態規劃裡的經典結構。最關鍵的是推出狀態轉移方程,當前規模的對應解法由更低規模的解法,彷彿拾級而上,站在前人的肩膀上不斷攀登。

實際操作起來,比較實用的方法如下:固定一個比較小的規模n, 進行思維實驗。

例子:

nums = [2,7,9,3,1],求這個陣列對應的最高金額。

 我們要做的是拿著某個規模的解,去求更高規模的解。用陣列memo記錄每個規模對應的解(最高金額),memo[i]對應的是nums的子陣列nums[:i](子問題)對應的解(最高金額)。這個過程就是從左向右順序掃描nums陣列,一邊掃描一邊將求出的解儲存為memo[i]。假定現在掃描到i = 3,此時子陣列為nums[:3] = [2,7,9],我們來手算一下memo,得到memo[:3] = [2, 7, 11]。

好了,現在掃描到nums下一項,i = 4,nums[:4] = [2,7,9,3],現在我們來求memo的第四項,也就是下一規模的解。對應這第四個屋子(nums[3] = 3),作為一個賊我們有兩個選擇:偷或是不偷。如果我沒有偷第三家屋子,那就不用擔心偷第四家會觸發報警,那就放心偷好了;如果我偷了第三家,那就要斟酌一下偷不偷第四家了。偷第四家就必定要放棄第三家,但如果第四家錢特別多,那還是不虧的。i = 3時我們的選擇是偷2 和 9,收益是11;i = 4時,如果偷3就只能 7+3,收益是10,不划算,果斷不偷。memo更新為[2,7,11,11]。

類似地,繼續掃描,i = 5,nums[:5] = [2,7,9,3,1],還是那個問題——這家屋子偷還是不偷。因為我們放棄了第四家,不存在相鄰問題,放心偷就好。

發現規律了嗎?下一規模的解,也就是memo[n],要麼是memo[n-1] (不偷,保持原狀),或是memo[n-2]+nums[n](放棄上一家,偷這家)。由於程式不知道上一家有沒有偷,我們兩個選擇都算一下,取較大值即可。

程式碼:

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if nums == []:  return 0
        n = len(nums)
        if n == 1:  return nums[0]
        memo = [nums[0] for i in range(n)]
        memo[1] = max(nums[:2])
        for i in range(2,n):
            choice1 = memo[i-1]
            choice2 = memo[i-2]+nums[i]
            memo[i] = max(choice1,choice2)
        return memo[n-1]