LeetCode-337-打家劫舍III

思路
用爷爷,儿子(2),孙子(4)来解释,由题意知道,相邻节点不能偷。那么可知最大偷法只有2种:
爷爷+孙子(4)偷或者儿子(2)偷
方法一:暴力递归
int res1 = root.val + rob(root.left.left) + rob(root.left.right) + rob(root.right.left) + rob(root.right.right)
int res2 = rob(root.left) + rob(root.right);
挑选一个钱数多的方案则
int result = Math.max(res1, res2);
方法二:记忆化搜索
发现当我们递归计算爷爷节点时,其实也算了儿子和孙子节点。当儿子作为根节点时又重复计算。其实可以使用哈希表保存计算结果。当将要发生重复计算时,直接返回即可。
HashMap<TreeNode, Integer> memo = new HashMap<>();
return robInternal(root, memo);
方法三:
每个节点可选择偷或者不偷两种状态
当前节点选择偷时,那么两个孩子节点就不能选择偷了
当前节点选择不偷时,两个孩子节点只需要拿最多的钱出来就行(两个孩子节点偷不偷没关系)
我们使用一个大小为 2 的数组来表示 int[] res = new int[2]
0 代表不偷,1 代表偷
/*任何一个节点能偷到的最大钱的状态可以定义为
当前节点选择不偷:当前节点能偷到的最大钱数 = 左孩子能偷到的钱 + 右孩子能偷到的钱
当前节点选择偷:当前节点能偷到的最大钱数 = 左孩子选择自己不偷时能得到的钱 + 右孩子选择不偷时能得到的钱 + 当前节点的钱数
表示为公式如下*/
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;
代码
//方法一(超时)
public int rob(TreeNode root) {
if(root==null)return 0;
int res1=root.val;
if(root.left!=null) res1+=rob(root.left.left)+rob(root.left.right);
if(root.right!=null) res1+=rob(root.right.left)+rob(root.right.right);
int res2=rob(root.left)+rob(root.right);
return Math.max(res1,res2);
}
//方法二
public int rob(TreeNode root) {
HashMap<TreeNode, Integer> memo = new HashMap<>();
return robInternal(root, memo);
}
public int robInternal(TreeNode root, HashMap<TreeNode, Integer> memo) {
if (root == null) return 0;
if (memo.containsKey(root)) return memo.get(root);
int money = root.val;
if (root.left != null) {
money += (robInternal(root.left.left, memo) + robInternal(root.left.right, memo));
}
if (root.right != null) {
money += (robInternal(root.right.left, memo) + robInternal(root.right.right, memo));
}
int result = Math.max(money, robInternal(root.left, memo) + robInternal(root.right, memo));
memo.put(root, result);
return result;
}
//方法三
public int rob(TreeNode root) {
int []res=helper(root);
return Math.max(res[0],res[1]);
}
public int[] helper(TreeNode root){
int []res=new int[2];
if(root==null)return res;
int []left=helper(root.left);
int []right=helper(root.right);
res[0]=Math.max(left[0],left[1])+Math.max(right[0],right[1]);
res[1]=left[0]+right[0]+root.val;
return res;
}
本文介绍了如何使用深度优先搜索和记忆化技术解决LeetCode题目337——打家劫舍III。通过三种方法对比,包括暴力递归、哈希表记忆化和状态转移数组,展示了如何避免重复计算,优化算法效率。
821

被折叠的 条评论
为什么被折叠?



