(动归模板讲解的妙啊)(注意dp[k] 是前k间房子的最大值,最后一间房子是nums[k-1], 不是nums[k]) (用 prev 和 curr 来代替dp[k-2] 和 dp[k-1], 用 tem 来代替 dp[k]
文章目录
动归模板讲解绝了
题目
代码
dp[k] 代表从前k间房子能获得的最多的钱,不能偷相邻房子的钱,从0 —> k ,这样,在算后面的dp[k]的时候。前面的dp值早都求出来了
for循环里 i <= nums.length; 而不是i <=nums.length-1; 因为要求前nums.length间房子能取得的钱,注意把握dp数组的含义。(而且也不会访问nums[i],所以不会越界,本题唯一绕人的地方就在这)
class Solution {
public int rob(int[] nums) {
if(nums.length == 1){
return nums[0];
}
int[] dp = new int[nums.length+1]; // dp[k] 代表从前k间房子能获得的最多的钱,不能偷相邻房子的钱,从0 —> k ,这样,在算后面的dp[k]的时候。前面的dp值早都求出来了
// 初始化
dp[0] = 0;
dp[1] = nums[0];
for(int i = 2; i <= nums.length; i++){ // 这里 i <= nums.length; 而不是i <=nums.length-1; 因为要求前nums.length间房子能取得的钱,注意把握dp数组的含义。(而且也不会访问nums[i],所以不会越界,本题唯一绕人的地方就在这)
dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i-1]); // 注意:当前处理的前 i 个房子 的最后一个房子是nums[i-1], 不是 nums[i]
}
return dp[nums.length]; // 返回值 是 dp[nums.length],代表从前nums.length - 1个房子所能获得的最多的钱,而不是dp[nums.length-1];
}
}
空间优化后的代码
class Solution {
public int rob(int[] nums) {
int prev = 0; // 一开始代表 0
int curr = 0; // 一开始代表 0
// 每次循环,计算“偷到当前房子为止的最大金额”
for (int i : nums) { // 从第 0 个开始 ,一次循环过后 prev就得值就变成了dp[0], curr就变成了 dp[1]
// 循环开始时,curr 表示 dp[k-1],prev 表示 dp[k-2]
// dp[k] = max{ dp[k-1], dp[k-2] + i }
int temp = Math.max(curr, prev + i);
prev = curr;
curr = temp;
// 循环结束时,curr 表示 dp[k],prev 表示 dp[k-1]
}
return curr;
}
}
// @solution-sync:end