0%

打家劫舍

打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

1
2
3
4
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
  偷窃到的最高金额 = 1 + 3 = 4 。

思路1: 递归实现,以任一个房屋开始,对于下一个不触发警报的房屋进行决策:是否偷他?! 然后对于不同的状况继续进行偷取. 在每一次偷取成功后就尝试更新最大偷盗金额.

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution {
int max = 0;
public int rob(int[] nums) {
rob(nums, 0, 0, null);
return max;
}

/**
* home 当前偷到哪一个房子了
* money 当前偷了多少钱了
* last 最后一个偷的房间
*/
public void rob(int[] nums, int home, int money, Integer last) {
max = Math.max(max, money);
if(home >= nums.length) {
return;
}
for(int i = home; i < nums.length; i++) {
if(last == null) {
rob(nums, i, nums[i] + money, i);
} else {
// 确认不会触发报警
if(i > last + 1) {
// 偷,然后继续下一个房间
rob(nums, i, nums[i] + money, i);
}
}
if(last == null) {
rob(nums, i+1, money, i+1);
} else {
if(i > last + 1) {
// 不偷,继续下一个房间
rob(nums, i + 1, money, i + 1);
}

}
}
}
}

思路2: 动态规划, 定义dp数组, dp[i] 代表到第i位最大的金额,存在状态转移关系:

1
2
dp[i] = nums[i] i == 0
dp[i] = max(nums[i], dp[i-1], dp[i-1]) i > 0, i > 1

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
int max = 0;
public int rob(int[] nums) {
int length = nums.length;
int[] dp = new int[length];
for(int i = 0; i < length; i++) {
if(i == 0) {
dp[i] = nums[i];
} else {
int last = i - 2;
int last2 = i - 1;
if(last2 >= 0) {
dp[i] = Math.max(dp[i], dp[i - 1]);
}
if(last >= 0) {
dp[i] = Math.max(dp[last] + nums[i], dp[i]);
}
dp[i] = Math.max(dp[i], nums[i]);

}
}
return dp[length - 1];
}
}