代码随想录算法训练营第四十七天丨198. 打家劫舍、 213. 打家劫舍 II、337. 打家劫舍 III

198. 打家劫舍

自己的思路:

初始化两个dp数组,dp[i][0]表示不偷第i户,在0-i户可以偷到的最大金额,dp[i][1]表示偷i户在0-i户可以偷到的最大金额。

python 复制代码
class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [[0] * 2 for _ in range(n)]
        dp[0][1] = nums[0]
        for i in range(1, n):
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1])
            dp[i][1] = dp[i - 1][0] + nums[i]
        return max(dp[n - 1][0], dp[n - 1][1])

优化:

有一点臃肿,可以优化。dp[i][1]实际上跟dp[i-1][1]就没啥关系,直接把dp数组初始化成一维的就行了。

python 复制代码
class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 1:
            return nums[0]
        if n == 2:
            return max(nums[0], nums[1])
        
        dp = [0] * n
        dp[0] = nums[0]
        dp[1] = max(nums[0], nums[1])
        
        for i in range(2, n):
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])
        
        return dp[n - 1]

更优化:

想起了斐波那契数列...

python 复制代码
class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 1:
            return nums[0]
        if n == 2:
            return max(nums[0], nums[1])
        
        prev = nums[0]
        cur = max(nums[0], nums[1])
        for i in range(2, n):
            prev, cur = cur, max(cur, prev + nums[i])
        return cur

213. 打家劫舍 II

还是比较容易想到的,把环展成两个线性的,一个去头一个去尾即可。

python 复制代码
class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 1:
            return nums[0]
        if n == 2:
            return max(nums[0], nums[1])
        
        def helper(n, nums):
            dp = [0] * n
            dp[0] = nums[0]
            dp[1] = max(nums[0], nums[1])
            for i in range(2, n):
                dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])
            return dp[n - 1]
        
        return max(helper(n-1, nums[1:]), helper(n-1, nums[:-1]))

337. 打家劫舍 III

我的思路:

有点类似贪心的最后一题。

一顿操作AC了,中间遗漏了几种情况,修改后正确了。

python 复制代码
class Solution:
    def rob(self, root: Optional[TreeNode]) -> int:
        def helper(root):
            if not root.left and not root.right:
                return 0, root.val
            elif root.left and root.right:
                left_without_self, left_with_self = helper(root.left)
                right_without_self, right_with_self = helper(root.right)
                return max(left_without_self + right_without_self, left_with_self + right_with_self, left_without_self + right_with_self, left_with_self + right_without_self), left_without_self + right_without_self + root.val
            elif root.left and not root.right:
                left_without_self, left_with_self = helper(root.left)
                return max(left_with_self, left_without_self), left_without_self + root.val
            elif root.right and not root.left:
                right_without_self, right_with_self = helper(root.right)
                return max(right_with_self, right_without_self), right_without_self + root.val
        return max(helper(root))

优化:

终止条件从叶子节点改成空节点,可以将之后的情况全部统一起来。

python 复制代码
class Solution:
    def rob(self, root: Optional[TreeNode]) -> int:
        def helper(root):
            if not root:
                return 0, 0
            left = helper(root.left)
            right = helper(root.right)
            not_include = max(left) + max(right)
            include = left[0] + right[0] + root.val
            return not_include, include
        return max(helper(root))

带备忘的递归:

python 复制代码
class Solution:
    def rob(self, root: Optional[TreeNode]) -> int:
        memo = {}

        def helper(node):
            if not node:
                return 0
            
            if node in memo:
                return memo[node]
            
            val = node.val
            # 如果偷当前节点,则不能偷其直接的左右子节点,但可以偷其孙子节点
            if node.left:
                val += helper(node.left.left) + helper(node.left.right)
            if node.right:
                val += helper(node.right.left) + helper(node.right.right)
            
            # 不偷当前节点,可以偷其左右子节点
            not_steal = helper(node.left) + helper(node.right)
            
            # 对于当前节点,选择偷与不偷的最大值
            result = max(val, not_steal)
            memo[node] = result
            return result
        
        return helper(root)

今日总结:

自己写能AC,都能get到要点~~~精简的代码还是得看题解。

相关推荐
姜威鱼6 分钟前
蓝桥杯python编程每日刷题 day 21
数据结构·算法·蓝桥杯
CYRUS STUDIO14 分钟前
Unidbg Trace 反 OLLVM 控制流平坦化(fla)
android·汇编·算法·网络安全·逆向·ollvm
ゞ 正在缓冲99%…21 分钟前
leetcode22.括号生成
java·算法·leetcode·回溯
小卡皮巴拉32 分钟前
【力扣刷题实战】矩阵区域和
开发语言·c++·算法·leetcode·前缀和·矩阵
WG_1740 分钟前
第五章.图论
算法·图论
神里流~霜灭1 小时前
蓝桥备赛指南(12)· 省赛(构造or枚举)
c语言·数据结构·c++·算法·枚举·蓝桥·构造
小杨爱学习zb1 小时前
学习总结 网格划分+瞬态求解设置
笔记·学习·算法
双叶8361 小时前
(C语言)单链表(1.0)(单链表教程)(数据结构,指针)
c语言·开发语言·数据结构·算法·游戏
uhakadotcom2 小时前
OpenAI 的 PaperBench:AI 研究复现基准测试工具
算法·面试·github
凯强同学2 小时前
第十四届蓝桥杯大赛软件赛省赛Python 大学 C 组:6.棋盘
python·算法·蓝桥杯