代码随想录第48天|198. 打家劫舍、213. 打家劫舍 II、337. 打家劫舍 III

86 阅读2分钟

198. 打家劫舍

1. doc reading

代码随想录 (programmercarl.com) 先看看正确的思路

class Solution:
    def rob(self, nums: List[int]) -> int:
        # 1. dp[i]表示考虑偷不偷第i号房屋时最大的偷窃总金额。
        dp = [0] * len(nums)
        # 2. 递推关系是:
        # 2.1. 如果偷第i号,那i-1号一定不偷,我们应该直接考虑dp[i-2]代表的最大总金额。
        # 2.2. 如果不偷第i号, 那我们当前的最大盗窃金额一定是 dp[i-1] 代表的最大总金额,这个总金额可能是偷了i-1号的也可能是没有偷的,这不重要,但是一定是考虑过i-1号的。
        # 3. 初始化:第0号一定是nums[0], 第1号一定是max(nums[0], nums[1]), 因为只能从这两个里面选一个。
        dp[0] = nums[0]
        if len(nums) == 1:
            return dp[0]
        dp[1] = max(nums[0], nums[1])
        for idx in range(2, len(nums)):
            dp[idx] = max(dp[idx - 2] + nums[idx], dp[idx - 1])
        return dp[-1]

213. 打家劫舍 II

1. first idea

这次组成了一个环。 所以第一个和最后一个不能同时偷。 那么如何才能保证这一点的情况下构建状态转换表呢?

2. doc reading

代码随想录 (programmercarl.com)

  • 情况一:考虑不包含首尾元素
  • 情况二:考虑包含首元素,不包含尾元素
  • 情况三:考虑不包含首元素,包含尾元素

因为包含也是考虑包含而不是一定包含,所以情况二和三能够涵盖情况一。

所以我们只需要做两次动态规划。

class Solution:
    def build_dp(self, nums):
        if len(nums) == 1:
            return nums[0]
        dp = [0] * len(nums)
        dp[0] = nums[0]
        dp[1] = max(nums[0], nums[1])
        for idx in range(2, len(nums)):
            dp[idx] = max(dp[idx - 1], dp[idx - 2] + nums[idx])
        return dp[-1]

    def rob(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return nums[0]
        max_val_head = self.build_dp(nums[: -1])
        max_val_tail = self.build_dp(nums[1:])
        return max(max_val_head, max_val_tail)

337. 打家劫舍 III

1. doc reading

代码随想录 (programmercarl.com)

本题一定是要后序遍历,因为通过递归函数的返回值来做下一步计算

与198.打家劫舍,213.打家劫舍II一样,关键是要讨论当前节点抢还是不抢。

如果抢了当前节点,两个孩子就不能动,如果没抢当前节点,就可以考虑抢左右孩子.

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def post_dfs(self, root):
        if root is None:
            return [0, 0]  # not rob, rob
        else:
            left_robornot = self.post_dfs(root.left)
            right_robornot = self.post_dfs(root.right)
            # rob root
            rob_val = (left_robornot[0] + right_robornot[0]) + root.val
            # not rob root
            notrob_val = max(left_robornot) + max(right_robornot)
            # print([notrob_val, rob_val])
            return [notrob_val, rob_val]

    def rob(self, root: Optional[TreeNode]) -> int:
        rob_or_not = self.post_dfs(root)
        return max(rob_or_not)