<代码随想录> 算法训练营-2024.12.21

发布于:2025-02-11 ⋅ 阅读:(126) ⋅ 点赞:(0)

今日专题 :动态规划、打家劫舍

总结:

198. 打家劫舍
class Solution:
    def rob(self, nums: List[int]) -> int:
        #dp[n]=max(dp[n-1],dp[n-2]+nums[n])
        size=len(nums)
        if size==1:
            return nums[0]
        #n的状态只依赖n-1和n-2的状态,对状态进行压缩
        i,j=nums[0],max(nums[0],nums[1])
        result=max(i,j)
        for n in range(2,size):
            result=max(j,i+nums[n])
            i,j=j,result
        
        return result

       

213. 打家劫舍 II

思路:环形的打家劫舍

class Solution:
    def rob(self, nums: List[int]) -> int:
        # 环形的打家劫舍
        # 计算两个最大值 偷0 和不偷0
        # 偷0 则dp从2开始 size-2
        # 不偷0 dp从1开始到 size-1

        def robs(numList):
            if len(numList) < 2:
                return numList[0]
            i, j = 0, 0
            res = j
            for n in numList:
                res = max(j, i + n)
                i, j = j, res
            return res

        size = len(nums)

        if size <= 3:
            return max(nums)
        return max(robs(nums[2 : size - 1]) + nums[0], robs(nums[1:]))

337. 打家劫舍 III

思路:关键点在于把当前层选没选传递下去
1.如果上层节点没有被选,则当前节点可选可不选取最大值
2.如果上层节点被选,则当前节点只能不选

总结:以下解法一为我根据上述思路做出来的解法,其实不属于动态规划解法,每个节点被遍历两次,解法二从下往上返回不同选择的结果,并用子问题的结果一步步构建到根节点的结果
解法一:

# 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 rob(self, root: Optional[TreeNode]) -> int:
        # 树形打家劫舍
        @cache
        def dfs(node, flag):
            if node == None:
                return 0
            res1, res2 = 0, 0
            if node.left:
                res1 += dfs(node.left, False)
            if node.right:
                res1 += dfs(node.right, False)
            if not flag:
                res2 += node.val
                if node.left:
                    res2 += dfs(node.left, True)
                if node.right:
                    res2 += dfs(node.right, True)

            return max(res1, res2)

        return dfs(root, False)

解法二

# 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 rob(self, root: Optional[TreeNode]) -> int:
        # dp数组(dp table)以及下标的含义:
        # 1. 下标为 0 记录 **不偷该节点** 所得到的的最大金钱
        # 2. 下标为 1 记录 **偷该节点** 所得到的的最大金钱
        dp = self.traversal(root)
        return max(dp)

    # 要用后序遍历, 因为要通过递归函数的返回值来做下一步计算
    def traversal(self, node):
        
        # 递归终止条件,就是遇到了空节点,那肯定是不偷的
        if not node:
            return (0, 0)

        left = self.traversal(node.left)
        right = self.traversal(node.right)

        # 不偷当前节点, 偷子节点
        val_0 = max(left[0], left[1]) + max(right[0], right[1])

        # 偷当前节点, 不偷子节点
        val_1 = node.val + left[0] + right[0]

        return (val_0, val_1)

网站公告

今日签到

点亮在社区的每一天
去签到