打家劫舍

选择:抢还是不抢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public int rob(int[] nums) {
int n = nums.length;
//记录最近的两个状态
int dp_i_1 = 0, dp_i_2 = 0;
int dp_i = 0;
for (int i = n - 1; i >= 0; i--) {
dp_i = Math.max(dp_i_1, nums[i] + dp_i_2);
dp_i_2 = dp_i_1;
dp_i_1 = dp_i;
}
return dp_i;
}
}

打家劫舍 II

分别判断两种情况谁收益更高:取头或取尾

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if (n == 1) {
return nums[0];
}
return Math.max(robRange(nums, 0, n - 2), robRange(nums, 1, n - 1));
}

private int robRange(int[] nums, int start, int end) {
int n = nums.length;
int dp_i_1 = 0, dp_i_2 = 0;
int dp_i = 0;
for (int i = end; i >= start; i--) {
dp_i = Math.max(dp_i_1, dp_i_2 + nums[i]);
dp_i_2 = dp_i_1;
dp_i_1 = dp_i;
}
return dp_i;
}
}

打家劫舍 III

1
2
3
4
5
6
7
8
9
10
class Solution {
public int rob(TreeNode root) {
if (root == null) return 0;
int val1 = root.val;
if (root.left != null) val1 += rob(root.left.left) + rob(root.left.right);
if (root.right != null) val1 += rob(root.right.left) + rob(root.right.right);
int val2 = rob(root.left) + rob(root.right);
return Math.max(val1, val2);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
private Map<TreeNode, Integer> map = new HashMap<>();

public int rob(TreeNode root) {
if (root == null) {
return 0;
}
if (map.containsKey(root)) {
return map.get(root);
}
//偷
int do_it = root.val + (root.left == null ? 0 : rob(root.left.left) + rob(root.left.right)) + (root.right == null ? 0 : rob(root.right.left) + rob(root.right.right));
//不偷
int not_do = rob(root.left) + rob(root.right);
int res = Math.max(do_it, not_do);
map.put(root, res);
return res;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public int rob(TreeNode root) {
int[] res = dp(root);
return Math.max(res[0], res[1]);
}

/**
*
* @param root
* @return
* arr[0] 表示不抢 root 的话,得到的最大钱数
* arr[1] 表示抢 root 的话,得到的最大钱数
*/
private int[] dp(TreeNode root) {
if (root == null) {
return new int[]{0, 0};
}
int[] left = dp(root.left);
int[] right = dp(root.right);
int do_it =root.val + left[0] + right[0];
int not_do = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
return new int[]{not_do,do_it};

}
}

总结

关键就是选择 偷或者不偷,因为只是相邻的不能偷,所以需要记录的是最近两个状态。