更新:刷100遍也不会 我真是草履虫本虫 也找不到工作
纪念:发现力扣上做题数过百了 流下了激动的泪水 废物大学生2021能找到工作吗
题目
相关题目:
【刷题1】LeetCode 198. 打家劫舍 java题解
【刷题1】LeetCode 213. 打家劫舍 II java题解
本题题目:
LeetCode 337. 打家劫舍 III
方法一:动态规划
分析
对于一个结点o,用f(o)表示o被选中时的最大值,用g(o)表示o没被选中时最大值。用left和right表示孩子。
①o被选中时,它的孩子left和right一定不能被选中。
f(o)=o.val+g(left)+g(right)
②o没被选中时,它的孩子既可以被选中也可以不被选中。
g(o)=max(g(left),f(left))+max(g(right),f(right))
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
//f被选中,g没被选中
HashMap<TreeNode,Integer> f=new HashMap<>();
HashMap<TreeNode,Integer> g=new HashMap<>();
public int rob(TreeNode root) {
if(root==null)
return 0;
dfs(root);
return Math.max(f.getOrDefault(root,0),g.getOrDefault(root,0));
}
public void dfs(TreeNode root){
if(root==null)
return;
dfs(root.left);
dfs(root.right);
f.put(root,root.val+g.getOrDefault(root.left,0)+g.getOrDefault(root.right,0));
g.put(root,Math.max(f.getOrDefault(root.left,0),g.getOrDefault(root.left,0))
+Math.max(f.getOrDefault(root.right,0),g.getOrDefault(root.right,0)));
}
}
我们可以看出,以上的算法对二叉树做了一次后序遍历。
复杂度
时间复杂度是 O(n);
由于递归会使用到栈空间,空间代价是O(n),哈希映射的空间代价也是O(n),故空间复杂度也是 O(n)。
方法二:空间优化过的方法一
分析
我们可以做一个小小的优化,我们发现无论是 f(o)还是g(o),他们最终的值只和f(l)、g(l)、f®、g® 有关,所以对于每个节点,我们只关心它的孩子节点们的 f和 g 是多少。我们可以设计一个结构,表示某个节点的 f 和 g 值,在每次递归返回的时候,都把这个点对应的 f 和 g 返回给上一级调用,这样可以省去哈希映射的空间。
代码
class Solution {
public int rob(TreeNode root) {
int[] rootStatus = dfs(root);
return Math.max(rootStatus[0], rootStatus[1]);
}
public int[] dfs(TreeNode node) {
if (node == null) {
return new int[]{0, 0};
}
int[] l = dfs(node.left);
int[] r = dfs(node.right);
int selected = node.val + l[1] + r[1];
int notSelected = Math.max(l[0], l[1]) + Math.max(r[0], r[1]);
return new int[]{selected, notSelected};
}
}
复杂度
时间复杂度:O(n)。同方法一。
空间复杂度:O(n)。虽然优化过的版本省去了哈希映射的空间,但是栈空间的使用代价依旧是 O(n),故空间复杂度不变。
结果
方法三:直接搜索
悲伤的是我连这个方法都想不出来
//true表示root结点可以用,false表示根结点不可以用,能通过,击败5.03%
class Solution {
public int rob(TreeNode root) {
//root结点当然是可以用的
return dfs(root,true);
}
private static int dfs(TreeNode root, boolean flag) {
if (root == null) {
return 0;
}
if (flag) { //当前结点能用,我们可以用,也可以不用
return Math.max(root.val + dfs(root.left, false) + dfs(root.right, false), dfs(root.left, true) + dfs((root.right), true));
} else { //当前结点不可以用,我们一定不能用
return dfs(root.left, true) + dfs(root.right, true);
}
}
}