返回

盗亦有道:打家劫舍 III 的妙招奇思

前端

盗亦有道:打家劫舍 III 的妙招奇思

在夜幕降临之际,窃贼罗宾悄然潜入一户富丽堂皇的豪宅。豪宅的每一间房屋都存放着数量不等的财富,罗宾的目标是窃取尽可能多的财富,但有一个限制:他不能窃取相邻的房屋。

面对这个难题,罗宾灵机一动,想到了一个巧妙的策略。他将豪宅抽象成一棵二叉树,其中每个节点代表一间房屋,而节点的值则代表该房屋中存放的财富。罗宾需要找到一种方法,在不窃取相邻房屋的情况下,窃取到二叉树中最大的财富。

后序遍历的动态规划

罗宾决定采用后序遍历的动态规划方法来解决这个问题。后序遍历是一种遍历二叉树的经典方法,它按照以下顺序访问节点:左子树、右子树、根节点。

在后序遍历的过程中,罗宾将维护两个动态规划变量:robnot_robrob 表示窃取当前节点的财富,而 not_rob 表示不窃取当前节点的财富。对于每个节点,罗宾需要计算 robnot_rob 的最大值,并将其存储在该节点上。

递推公式

罗宾推导出以下递推公式:

rob = max(not_rob + val, rob_left + rob_right)
not_rob = max(rob_left, rob_right)

其中:

  • val 是当前节点的财富。
  • rob_left 是当前节点左子树中竊取最大财富。
  • rob_right 是当前节点右子树中竊取最大财富。

算法步骤

基于上述递推公式,罗宾制定了以下算法步骤:

  1. 后序遍历二叉树。
  2. 对于每个节点:
    • 计算 robnot_rob 的值。
    • robnot_rob 的最大值存储在该节点上。
  3. 返回根节点的 rob 值,即为二叉树中可以窃取的最大财富。

示例

考虑以下二叉树:

        10
       /  \
      5    15
     / \   / \
    2   3 10  15

使用后序遍历的动态规划方法,我们可以计算出每个节点的 robnot_rob 值,如下表所示:

节点 val rob not_rob
2 2 2 0
3 3 3 0
5 5 7 5
10 10 15 10
15 15 15 15

因此,罗宾可以在不窃取相邻房屋的情况下,窃取到二叉树中的最大财富:30 元。

妙招奇思

打家劫舍 III 的解题精髓在于巧妙地利用了后序遍历和动态规划技术。后序遍历确保了罗宾在计算每个节点的 robnot_rob 值时,已经掌握了其子树中的最大财富信息。动态规划则允许罗宾将复杂问题分解为一系列较小的子问题,并逐层解决。

此外,递推公式的精妙之处在于,它不仅考虑了当前节点的财富,还考虑了其子树中竊取最大财富的可能性。通过最大化 robnot_rob 的值,罗宾可以找到二叉树中窃取最大财富的最佳策略。

结语

打家劫舍 III 是一道经典的动态规划问题,它考验着我们对后序遍历和动态规划技术的理解。通过深入浅出的讲解和丰富的示例,本文揭示了打家劫舍 III 的解题妙招和奇思。掌握这些技巧,我们将能够应对各种动态规划问题,从抢劫问题到背包问题,游刃有余,尽显编程之美。