由题意知:
一、暴力法:
根结点是爷爷,根结点的左右孩子结点是两个孩子,孩子的孩子是孙子
所以比较四个孙子vs两个儿子 这两个组合谁得钱多,就当做当前结点的最大钱数,
4 个孙子投的钱加上爷爷的钱如下
int method1 = root.val + rob(root.left.left) + rob(root.left.right) + rob(root.right.left) + rob(root.right.right)
两个儿子偷的钱如下
int method2 = rob(root.left) + rob(root.right);
挑选一个钱数多的方案则
int result = Math.max(method1, method2);
1 public int rob(TreeNode root) { 2 if (root == null) return 0; 3 4 int money = root.val; 5 if (root.left != null) { 6 money += (rob(root.left.left) + rob(root.left.right)); 7 } 8 9 if (root.right != null) { 10 money += (rob(root.right.left) + rob(root.right.right)); 11 } 12 13 return Math.max(money, rob(root.left) + rob(root.right)); 14 }
二、记忆化搜索
在方法一种,发现在计算爷爷时,已经计算了一次孙子的值,所以在儿子当爷爷时,会重复计算一遍孙子结点
所以我们把计算的值存下来,下次再用就直接从里面取出来,只需一次计算
因为二叉树不方便用数组,所以用哈希表存计算结果
1 public int rob(TreeNode root) { 2 HashMap<TreeNode,Integer> memo=new HashMap<>(); 3 return rob_2(root,memo); 4 } 5 public static int rob_2(TreeNode root,HashMap<TreeNode,Integer> memo){ 6 if(root==null) 7 return 0; 8 if(memo.containsKey(root)) 9 return memo.get(root); 10 int money=root.val; 11 if(root.left!=null){ 12 money+=(rob_2(root.left.left,memo)+rob_2(root.left.right,memo)); 13 } 14 if(root.right!=null){ 15 money+=(rob_2(root.right.left,memo)+rob_2(root.right.right,memo)); 16 } 17 int res=Math.max(money,rob_2(root.left,memo)+rob_2(root.right,memo)); 18 memo.put(root,res); 19 return res; 20 }
三、最终
任何一个节点能偷到的最大钱的状态可以定义为
当前节点选择不偷:当前节点能偷到的最大钱数 = 左孩子能偷到的钱 + 右孩子能偷到的钱
当前节点选择偷:当前节点能偷到的最大钱数 = 左孩子选择自己不偷时能得到的钱 + 右孩子选择不偷时能得到的钱 + 当前节点的钱数
root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) + Math.max(rob(root.right)[0], rob(root.right)[1])
root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val;
1 public int rob(TreeNode root) { 2 int[] result = robInternal(root); 3 return Math.max(result[0], result[1]); 4 } 5 6 public int[] robInternal(TreeNode root) { 7 if (root == null) return new int[2]; 8 int[] result = new int[2]; 9 10 int[] left = robInternal(root.left); 11 int[] right = robInternal(root.right); 12 13 result[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]); 14 result[1] = left[0] + right[0] + root.val; 15 16 return result; 17 }