【LeetCode 刷题】动态规划(3)-打家劫舍

此博客为《代码随想录》动态规划章节的学习笔记,主要内容为动态规划打家劫舍问题的相关题目解析。

文章目录

  • 198. 打家劫舍
  • 213. 打家劫舍II
  • 337.打家劫舍 III

198. 打家劫舍

题目链接

class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0] * (n + 1)
        dp[0] = 0
        dp[1] = nums[0]
        for i in range(2, n + 1):
            dp[i] = max(dp[i-1], dp[i-2] + nums[i-1])
        return dp[n]
  • 状态定义:dp[i] 表示偷到第 i 个房子所能获得的最大金额(i 与实际下标相差 1)
  • 递推公式:dp[i] = max(dp[i-1], dp[i-2] + nums[i-1])
  • 初始化:dp[0] = 0dp[1] = nums[0]

213. 打家劫舍II

题目链接

class Solution:
    def rob(self, nums: List[int]) -> int:
        def dp_rob(nums: List[int]) -> int:
            n = len(nums)
            dp = [0] * (n + 1)
            dp[0] = 0
            dp[1] = nums[0]
            for i in range(2, n + 1):
                dp[i] = max(dp[i-1], dp[i-2] + nums[i-1])
            return dp[n]
            
        if len(nums) == 1:
            return nums[0]
        return max(dp_rob(nums[1:]), dp_rob(nums[:-1]))
  • 把 环状排列房间 问题约化为两个 单排排列房间 子问题:
    • 不偷窃第一个房子的情况下(即 nums[1:])取得最大金额 p1
    • 在不偷窃最后一个房子的情况下(即 nums[:n−1]),取得最大金额p2
    • 取两种子问题的最大值 max(p1, p2)

337.打家劫舍 III

题目链接

class Solution:
    def rob(self, root: Optional[TreeNode]) -> int:
        def dfs(node: Optional[TreeNode]) -> (int, int):
            if node is None:
                return 0, 0
            l_rob, l_not = dfs(node.left)
            r_rob, r_not = dfs(node.right)
            rob = l_not + r_not + node.val
            not_rob = max(l_rob, l_not) + max(r_rob, r_not)
            return rob, not_rob
        
        return max(dfs(root))
  • 树形 dp,每个节点的 dp 数组为长度为 2 的数组,分别保存选/不选该节点所能获得的最大金额
  • 后序遍历,每个节点只遍历一遍
  • 注意,不选当前节点时,最大金额为 max(l_rob, l_not) + max(r_rob, r_not) ,并不是 l_rob + r_rob

你可能感兴趣的:(LeetCode,leetcode,动态规划,算法,python)