The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "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 forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night.
Determine the maximum amount of money the thief can rob tonight without alerting the police.
Example 1:
Input: [3,2,3,null,3,null,1] 3 / 2 3 3 1 Output: 7 Explanation: Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.Example 2:
Input: [3,4,5,1,3,null,1] 3 / 4 5 / 1 3 1 Output: 9 Explanation: Maximum amount of money the thief can rob = 4 + 5 = 9.
打家劫舍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 robInternal(root, memo); 5 } 6 7 public int robInternal(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 += (robInternal(root.left.left, memo) + robInternal(root.left.right, memo)); 17 } 18 if (root.right != null) { 19 money += (robInternal(root.right.left, memo) + robInternal(root.right.right, memo)); 20 } 21 int res = Math.max(money, robInternal(root.left, memo) + robInternal(root.right, memo)); 22 memo.put(root, res); 23 return res; 24 } 25 }
最后是动态规划。创建一个数组,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 }