【算法思考记录】力扣337. 打家劫舍 III【Python3,树上DP】

337. 打家劫舍 III(中等)

题目概述

在题目“337. 打家劫舍 III”中,我们面对的是一个特殊的盗窃问题,设定在一种类似二叉树结构的社区中。小偷只能在不触发警报的情况下进行偷盗,规则是:如果两个直接相连的房子同一晚被盗,则会触发警报。目标是在这些限制下,实现最大的盗窃价值。

题目示例

  1. 示例 1: 输入为 root = [3,2,3,null,3,null,1],输出应为 7,因为选择第一个、第四个和最后一个节点的房子进行盗窃,总金额为 3 + 3 + 1 = 7
  2. 示例 2: 输入为 root = [3,4,5,1,3,null,1],输出应为 9,选择第二个和第三个节点的房子进行盗窃,总金额为 4 + 5 = 9

解题思路

这个问题可以用动态规划来解决。我们需要计算每个节点在被盗和不被盗两种情况下的最大盗窃金额,并从中选择最优解。

Python3代码实现

# 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:
        from functools import cache

        @cache
        def dp(node, fa_robed):
            if node is None: 
                return 0

            rob_this = 0
            if not fa_robed:
                rob_this = node.val + dp(node.left, True) + dp(node.right, True)

            do_not_rob_this = dp(node.left, False) + dp(node.right, False)

            return max(rob_this, do_not_rob_this)
        
        return dp(root, False)

解析

  • 递归函数 dp: 这个函数计算在当前节点下的最大盗窃金额。它接受两个参数:当前节点和父节点是否被盗。
  • 缓存优化: 使用 functools 中的 cache 装饰器,我们避免了对同一节点的重复计算,显著提高了效率。
  • 核心逻辑: 对于每个节点,我们都有两个选择:盗窃当前节点(如果父节点没被盗),或者不盗窃当前节点。我们选择这两种情况下的最大值。

总结

这个问题是一个很好的动态规划问题实例,它展示了如何在树结构中应用动态规划。代码中利用递归和缓存机制,有效地解决了重叠子问题,保证了高效的运算。


注意:本博客为示范性教程,实际编码练习时请根据具体题目要求和测试用例进行调整,因为力扣的测试用例可能会更新。

你可能感兴趣的:(算法,leetcode,职场和发展,python)