leetcode 第198題 打家劫舍, 第213題 打家劫舍 II , 第337題 打家劫舍 III(Python解法)

leetcode 第198題 打家劫舍, 第213題 打家劫舍 II , 第337題 打家劫舍 III(Python解法)

Leetcode中最聰明的小偷—做程序員不如做小偷!

問題分析

198題 打家劫舍

第一題比較簡單,具體如下:
在這裏插入圖片描述
首先該題可以看成是一個動態規劃的問題,即從一個很小的範圍開始求解,慢慢擴大到n個房子。由於不能偷連續的兩家,所以其狀態轉移方程可以寫爲:dp[n] += max(dp[n-2], dp[n-3])(n >= 3),該方程是在房間數大於等於3的情況下展開的,所以n=0,1,2要單獨考慮。最後返回的是倒數第一個和倒數第二個元素較大者。
此外,可以選擇不開闢額外空間,直接在原nums數組上操作。

213題 打家劫舍 II

第二題是第一題的升級版,此題中所有的房子不再是一字排開,而是圍城了一個圓環,與第一題不同之處在於,第一間房子和最後一間房子不能同時被盜。
在這裏插入圖片描述
該題下面有一個提示,就是將分兩次遍歷數組,由於第一個房子不能和最後一個房子同時被盜,那麼兩個數組分別爲nums[:n-1]和nums[1:n]。接下來對這兩個數組依次使用第一題的方法,返回兩次的最大值。
需要注意的是,這裏數組的長度n>=4, 在n=0,1,2,3時都要分別考慮。

337題 打家劫舍 III

第三題是最難的,此時的房子排列成了一個二叉樹,同樣還是不能同時盜竊兩個相連的房子。這一題大致的思想與上面一樣,都是使用動態規劃的思想求出子樹的最大值。
先從根節點開始不斷地使用遞歸函數處理左右節點,遞歸函數返回值有兩個,分別對應着兩種情況。第一個數代表的是偷竊當前節點的房子所能取得的最大值,這個值等於當前節點值加上左右節點各自孩子的最大值(如果存在的話,不能與自己直接相連的子節點相加);另一個值是不偷當前節點的房子時所能取到的最大值(值爲左節點與左節點孩子中較大者與右節點與右節點孩子中較大者相加求和)。葉子節點比較特殊,由於沒有子節點,所以可以返回的第一個數是葉子節點值,第二個數爲0。
在這裏我們下面這個樹做例子:
在這裏插入圖片描述
先使用遞歸函數一直到最左邊的節點,那麼葉子節點6, 7分別返回(6, 0), (7, 0)。遞歸函數回到節點4,此時4返回(4+0+0, max(6,0)+max(7,0)),即爲(4,13)。這樣一直不斷返回,直到最後返回函數的結果爲節點1的結果,從該結果中選取較大的作爲整個函數的返回值。

源碼

198題 打家劫舍`

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

213題 打家劫舍 II

class Solution:
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        if n == 0:
            return 0
        if n == 1:
            return nums[0]
        if n == 2:
            return max(nums[0], nums[1])
        if n == 3:
            return max(nums[0], nums[1], nums[2])
        dp = [0] * n
        dp[0],dp[1] = nums[0], nums[1]
        dp[2] = nums[2] + nums[0]
        for i in range(3, n-1):
            dp[i] = nums[i] + max(dp[i-2], dp[i-3])
        ret = max(dp[n-2], dp[n-3])
        print("1=", dp)
        dp[2] = nums[2]
        dp[3] = nums[1] + nums[3]
        for i in range(4, n):
            dp[i] = nums[i] + max(dp[i-2], dp[i-3])
        print("2=", dp)
        return max(ret, dp[n-1], dp[n-2])

337題 打家劫舍 III

class Solution:
    def rob(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if root:
            return max(self.func(root))
        return 0

    def func(self, root):
        lv = rv = (0, 0)
        if root.left:
            lv = self.func(root.left)
        if root.right:
            rv = self.func(root.right)
        return root.val + lv[1] + rv[1],  max(lv) + max(rv)

謝謝!

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章