动态规划09 | ● 198.打家劫舍 ● *213.打家劫舍II ● *337.打家劫舍III

198.打家劫舍

视频讲解:https://www.bilibili.com/video/BV1Te411N7SX
https://programmercarl.com/0198.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8D.html

  • 考点
    • 动态规划
    • 打家劫舍
  • 我的思路
    • 大体思路没问题,一些细节不太对,具体见视频讲解关键点总结
    • dp[i]的含义是,偷到当前(第i + 1个,因为i从0开始)房屋的时候,所能偷的最大价值
      • 如果偷当前房屋,dp[i]就等于dp[i - 2] + nums[i],因为偷得房屋不能相邻
      • 如果不偷当前房屋,dp[i]就等于dp[i - 1]
      • 取上面两个值里的较大值作为最终的dp[i]
    • 初始化:由于dp的递推公式依赖于前两个元素,所以需要对dp[0]和dp[1]进行初始化
    • 遍历顺序从前向后
  • 视频讲解关键点总结
    • 我的思路里唯一考虑不全面的地方,就在于初始化步骤
      • 需要时刻牢记dp数组的含义,dp[i]是偷到当前房屋时所能偷得金额的最大值,所以的dp[1]不是直接等于nums[1],而是应取nums[0]和nums[1]二者中的最大值
  • 我的思路的问题
    • 见视频讲解关键点总结
  • 代码书写问题
  • 可执行代码
class Solution:
    def rob(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return nums[0]
        elif len(nums) == 2:
            return max(nums[0], nums[1])
        dp = [0] * len(nums)
        dp[0] = nums[0]
        dp[1] = max(nums[0], nums[1])
        for i in range(2, len(nums)):
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
        return dp[-1]

*213.打家劫舍II

视频讲解:https://www.bilibili.com/video/BV1oM411B7xq
https://programmercarl.com/0213.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8DII.html

  • 考点
    • 动态规划
    • 打家劫舍
  • 我的思路
    • 思路其实没问题,本题就是分情况讨论(不取最后一个元素时包含第一个元素能偷的最大价值,取最后一个元素时不包含第一个元素时能偷得最大价值),然后求两种情况的最大值
  • 视频讲解关键点总结
    • 关键在于,对于环形问题,通过分情况讨论,把环形问题变为线性问题进行解决
  • 我的思路的问题
    • 没问题
  • 代码书写问题
    • 注意“取最后一个元素时不包含第一个元素时能偷得最大价值”时,dp数组和nums数组下标的选取
  • 可执行代码
class Solution:
    def rob(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return nums[0]
        elif len(nums) == 2:
            return max(nums[0], nums[1])
        dp = [0] * (len(nums) - 1)
        dp[0] = nums[0]
        dp[1] = max(nums[0], nums[1])
        for i in range(2, len(nums) - 1):
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
        max_without_last = dp[-1]
        dp_ = [0] * (len(nums) - 1)
        dp_[0] = nums[1]
        dp_[1] = max(nums[1], nums[2])
        for i in range(2, len(nums) - 1):
            dp_[i] = max(dp_[i - 2] + nums[i + 1], dp_[i - 1])
        return max(dp_[-1], max_without_last)

*337.打家劫舍III

视频讲解:https://www.bilibili.com/video/BV1H24y1Q7sY
https://programmercarl.com/0337.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8DIII.html

  • 考点
    • 动态规划
    • 打家劫舍+二叉树遍历
  • 我的思路
    • 二叉树后序遍历
    • 其它思路没想清楚
  • 视频讲解关键点总结
    • 关键点1,对于每个节点,有两种状态,取当前节点和不取当前节点
      • 如果取当前节点,计算一个取当前节点的最大价值
      • 如果不取当前节点,计算一个不取当前节点所能得到的最大价值
      • 将二者作为结果返回
    • 关键点2,二叉树应采用后序遍历
      • 因为要首先把子节点的情况分析清楚,之后再分析当前节点
    • 递归三部曲
      • 形参:当前节点;返回值:当前节点取与不取时分别的最大值作为dp数组返回,dp[0]为不取当前节点的最大值,dp[1]为取当前节点的最大值
      • 退出条件:如果当前节点为空,则返回0和0
      • 单层逻辑:
        • 计算当前节点的dp数组并返回
  • 我的思路的问题
    • 无思路
  • 代码书写问题
  • 可执行代码
class Solution:
    def tracing(self, root):
        if root is None:
            return 0, 0
        left_dp = self.tracing(root.left)
        right_dp = self.tracing(root.right)
        dp_0 = max(left_dp[0], left_dp[1]) + max(right_dp[0], right_dp[1])
        dp_1 = left_dp[0] + right_dp[0] + root.val
        return dp_0, dp_1

    def rob(self, root: Optional[TreeNode]) -> int:
        dp = self.tracing(root)
        return max(dp[0], dp[1])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值