198. House Robber
- dp[i]: 0到i家最大可以偷的金额
- 公式:dp[i] = Math.max(dp[i-2]+nums[i], dp[i-1]) 因为题目说了只要不相邻就可以
- 注意dp[i-1]不代表nums[i]一定加进来了(不代表i家一定被偷了)
- 注意dp[i-2]表示0到i-2家最大可以偷的金额,i-2家不一定被偷了
- 初始化:dp[0] = nums[0]; dp[1] = Math.max(nums[0], nums[1])
- Time Complexity: O(nums.length)
- Space Complexity: O(nums.length) -> 优化为O(1)
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) return nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(nums[0],nums[1]);
for (int i=2; i<nums.length; i++) {
dp[i] = Math.max(dp[i-1], dp[i-2]+nums[i]);
}
return dp[nums.length-1];
}
}
213. House Robber ii
- 考虑去尾,考虑去头,选max
- Time Complexity: O(nums.length)
- Space Complexity: O(nums.length) -> 优化为O(1)
// O(1)
class Solution {
public int rob(int[] nums) {
if (nums.length==1) return nums[0];
if (nums.length==2) return Math.max(nums[0], nums[1]);
// int[] dp1 = new int[nums.length-1];
int dp1first = nums[0];
int dp1second = Math.max(nums[0], nums[1]);
for (int i=2; i<nums.length-1; i++) {
int temp = dp1second;
dp1second = Math.max(dp1first+nums[i], dp1second);
dp1first = temp;
}
//int[] dp2 = new int[nums.length-1];
int dp2first = nums[1];
int dp2second = Math.max(nums[1], nums[2]);
for (int i=3; i<nums.length; i++) {
int temp = dp2second;
dp2second = Math.max(dp2first+nums[i], dp2second);
dp2first = temp;
}
return Math.max(dp1second, dp2second);
}
}
// O(n)
class Solution {
public int rob(int[] nums) {
if (nums.length==1) return nums[0];
if (nums.length==2) return Math.max(nums[0], nums[1]);
int[] dp1 = new int[nums.length-1];
dp1[0] = nums[0];
dp1[1] = Math.max(nums[0], nums[1]);
for (int i=2; i<nums.length-1; i++) {
dp1[i] = Math.max(dp1[i-2]+nums[i], dp1[i-1]);
}
int[] dp2 = new int[nums.length-1];
dp2[0] = nums[1];
dp2[1] = Math.max(nums[1], nums[2]);
for (int i=3; i<nums.length; i++) {
dp2[i-1] = Math.max(dp2[i-3]+nums[i], dp2[i-2]);
}
return Math.max(dp1[nums.length-2], dp2[nums.length-2]);
}
}
337. House Robber iii
- 最佳方法1: dp,状态标记递归
- dp[i][0] = 第i个node偷的最大值;dp[i][1] = 第i个node不偷的最大值
- 初始化:i=null, dp[root] = [0,0]
- 公式:dp[i][0] = root(第i个node).val + dp[root.left][1] + dp[root.right] + 1; dp[i][1] = Math.max(dp[root.left][0], dp[root.left][1]) + Math.max(dp[root.right[0], dp[root.right][1])
- 注意这里可以体现house robber所有问题都一样的地方,对于可以偷的第i个元素,并不代表一定要偷这第i个元素,而是应该Math.max(偷第i个元素,不偷第i个元素);
- 遍历顺序:PostOrder后序,需要left child, right child的结果来给出root的结果
- Time Complexity: O(n),每个节点只遍历了一次
- Space Complexity: O(log n),算上递推系统栈的空间
class Solution {
public int rob(TreeNode root) {
return Math.max(helper(root)[0], helper(root)[1]);
}
public int[] helper(TreeNode root) {
// 0: steal 1: not steal
if (root == null) return new int[]{0,0};
int[] left = helper(root.left);
int[] right = helper(root.right);
int steal = root.val + left[1] + right[1];
int notsteal = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
return new int[]{steal, notsteal};
}
}
class Solution {
public int rob(TreeNode root) {
if (root == null) return 0;
int steal = root.val;
if (root.left != null)
steal += rob(root.left.left) + rob(root.left.right);
if (root.right != null)
steal += rob(root.right.left) + rob(root.right.right);
return Math.max(steal, rob(root.left)+rob(root.right));
}
}
- 方法3: recursion递归去偷,memo记录状态
- 提前结束递归,用memo记录过的值:if (map.containsKey(root)) return map.get(root);
class Solution {
public int rob(TreeNode root) {
return helper(root, new HashMap<TreeNode, Integer>());
}
public int helper(TreeNode root, Map<TreeNode, Integer> map) {
if (root == null) return 0;
if (map.containsKey(root)) return map.get(root);
int steal = root.val;
if (root.left != null)
steal += helper(root.left.left, map) + helper(root.left.right, map);
if (root.right != null)
steal += helper(root.right.left, map) + helper(root.right.right, map);
int max = Math.max(steal, helper(root.left, map)+helper(root.right, map));
map.put(root, max);
return max;
}
}