法一:动态规划 和716最少花费爬楼梯思路一样 链接
- 确定dp数组(dp table)以及下标的含义:dp[i]的定义为到第i号房屋能偷窃到的最高金额为dp[i]
- 确定递推公式:可以有两个途径得到dp[i],一个是dp[i-1] 一个是dp[i-2]。所以 dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1])
- dp数组如何初始化:dp[0] = nums[0]; dp[1] = Math.max(nums[0], nums[1]);
- 确定遍历顺序
- 举例推导dp数组
// nums.length是大于等于1的
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if(n == 1){
return nums[0];
}
if(n == 2){
return Math.max(nums[0], nums[1]);
}
int[] dp = new int[n];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for(int i = 2; i < n; i++){
dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
}
return dp[n - 1];
}
}
或者:
class Solution {
public int rob(int[] nums) {
int n = nums.length;
int[] dp = new int[n + 2];
for (int i = 0; i < n; i++) {
dp[i + 2] = Math.max(dp[i + 1], dp[i] + nums[i]);
}
return dp[n + 1];
}
}
法二:递归 回溯
class Solution {
private int[] nums, memo;
public int rob(int[] nums) {
this.nums = nums;
int n = nums.length;
memo = new int[n];
Arrays.fill(memo, -1); // -1 表示没有计算过
return dfs(n - 1); // 从最后一个房子开始思考
}
// dfs(i) 表示从 nums[0] 到 nums[i] 最多能偷多少
private int dfs(int i) {
if (i < 0) { // 递归边界(没有房子)
return 0;
}
if (memo[i] != -1) { // 之前计算过
return memo[i];
}
int res = Math.max(dfs(i - 1), dfs(i - 2) + nums[i]);
memo[i] = res; // 记忆化:保存计算结果
return res;
}
}