lotus

贵有恒何必三更眠五更起 最无益只怕一日曝十日寒

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1. 题目

 

读题

https://leetcode.cn/problems/house-robber-iii/description/

 

好的,我可以给你一个图形化的示例。假设我们有这样一个二叉树:

    3
   / \
  4   5
 / \   \
1   3   1

我们可以用一个表格来表示每个节点的f0f1的值:

节点f0f1
1 1 0
3 3 0
1 1 0
4 4 + max(0, 1) + max(0, 3) = 8 max(1, 0) + max(3, 0) = 4
5 5 + max(0, 1) + max(0, 0) = 6 max(1, 0) + max(0, 0) = 1
3 3 + max(4, 8) + max(1, 6) = 14 max(8, 4) + max(6, 1) = 13

所以,最终的答案是max(f0(3), f1(3)) = max(14, 13) = 14

考查点

 

这道题的考查点是:

  • 如何用递归或动态规划来解决树形结构的问题。
  • 如何定义合适的状态和状态转移方程来表示问题的最优解。
  • 如何优化递归的效率,避免重复计算。
  • 如何用不同的编程语言来实现算法。

2. 解法

思路

思路是这样的:

  • 我们定义一个辅助函数helper,它接受一个树节点作为参数,返回一个长度为2的数组,表示抢劫或不抢劫该节点能得到的最大值。
  • 如果节点为空,我们返回[0, 0],表示没有钱可抢。
  • 如果节点不为空,我们先递归地计算它的左右子树的结果,分别存储在left和right数组中。
  • 然后,我们计算抢劫当前节点的最大值,就是当前节点的值加上不抢劫左右子树的最大值,即root.val + left[1] + right[1]。
  • 接着,我们计算不抢劫当前节点的最大值,就是抢劫或不抢劫左右子树的最大值之和,即Math.max(left[0], left[1]) + Math.max(right[0], right[1])。
  • 最后,我们返回这两个值组成的数组。

 

这道题的状态转移方程是:

f_0(root) = root.val + f_1(root.left) + f_1(root.right) 
f_1(root) = max(f_0(root.left), f_1(root.left)) + max(f_0(root.right), f_1(root.right))

其中,

$f_0(root)$表示抢劫当前节点的最大值,

$f_1(root)$表示不抢劫当前节点的最大值。

 

具体实现

public int rob(TreeNode root) {
    if (root == null) return 0;
    int[] result = helper(root);
    return Math.max(result[0], result[1]);
}

public int[] helper(TreeNode root) {
    if (root == null) return new int[2];
    int[] result = new int[2];
    int[] left = helper(root.left);
    int[] right = helper(root.right);
    // result[0]表示抢劫当前节点的最大值
    result[0] = root.val + left[1] + right[1];
    // result[1]表示不抢劫当前节点的最大值
    result[1] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
    return result;
}

  

3. 总结

posted on 2023-05-01 16:46  白露~  阅读(13)  评论(0编辑  收藏  举报