[LeetCode] 337. House Robber III

The thief has found himself a new place for his thievery again. There is only one entrance to this area, called root.

Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that all houses in this place form a binary tree. It will automatically contact the police if two directly-linked houses were broken into on the same night.

Given the root of the binary tree, return the maximum amount of money the thief can rob without alerting the police.

Example 1:

Input: root = [3,2,3,null,3,null,1]
Output: 7
Explanation: Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.

Example 2:

Input: root = [3,4,5,1,3,null,1]
Output: 9
Explanation: Maximum amount of money the thief can rob = 4 + 5 = 9.

Constraints:

  • The number of nodes in the tree is in the range [1, 104].
  • 0 <= Node.val <= 104

打家劫舍 III。

小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。

除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。

给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/house-robber-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题意跟前两个版本差不多,但是这次,小偷的目标换到一棵树了。给了一个树的根节点 root,规则是不能偷相邻两层的节点上的房子。问最大收益是多少。

我这里提供几种思路,代码执行速度由慢到快,都值得掌握。我参考了这个帖子

首先是比较朴素的递归。思路是如果偷了根节点的房子,则不能偷儿子节点。最后判断的是到底是从根节点偷的收益大还是从儿子节点偷的收益大。

时间O(n)

空间O(n)

Java实现

 1 class Solution {
 2     public int rob(TreeNode root) {
 3         // corner case
 4         if (root == null) {
 5             return 0;
 6         }
 7 
 8         // normal case
 9         int money = root.val;
10         if (root.left != null) {
11             money += rob(root.left.left) + rob(root.left.right);
12         }
13         if (root.right != null) {
14             money += rob(root.right.left) + rob(root.right.right);
15         }
16         return Math.max(money, rob(root.left) + rob(root.right));
17     }
18 }

 

再来是记忆化递归。第一种解法中间有很多重复计算,需要用 hashmap 把中间过程的值记录下来。

时间O(n)

空间O(n)

Java实现

 1 class Solution {
 2     public int rob(TreeNode root) {
 3         HashMap<TreeNode, Integer> memo = new HashMap<>();
 4         return helper(root, memo);
 5     }
 6 
 7     private int helper(TreeNode root, HashMap<TreeNode, Integer> memo) {
 8         if (root == null) {
 9             return 0;
10         }
11         if (memo.containsKey(root)) {
12             return memo.get(root);
13         }
14         int money = root.val;
15         if (root.left != null) {
16             money += helper(root.left.left, memo) + helper(root.left.right, memo);
17         }
18         if (root.right != null) {
19             money += helper(root.right.left, memo) + helper(root.right.right, memo);
20         }
21         // 在当前节点需要判断是偷当前位置的收益大还是偷当前节点的左右孩子的收益大
22         int res = Math.max(money, helper(root.left, memo) + helper(root.right, memo));
23         memo.put(root, res);
24         return res;
25     }
26 }

 

最后是动态规划。创建一个数组,res[0] 表示不偷当前节点,res[1] 表示偷当前节点。

时间O(n)

空间O(n)

Java实现

 1 class Solution {
 2     public int rob(TreeNode root) {
 3         int[] res = helper(root);
 4         // 当前节点不偷,偷
 5         return Math.max(res[0], res[1]);
 6     }
 7     
 8     private int[] helper(TreeNode root) {
 9         if (root == null) {
10             return new int[2];
11         }
12         int[] left = helper(root.left);
13         int[] right = helper(root.right);
14         int[] res = new int[2];
15         res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
16         res[1] = root.val + left[0] + right[0];
17         return res;
18     }
19 }

 

LeetCode 题目总结

posted @ 2020-08-05 01:49  CNoodle  阅读(209)  评论(0编辑  收藏  举报