leetcode 198 House Robber
两种方式思考状态转移方程:
- robberedMoney [i]=max(robberedMoney[i-k]){ 其中2<=k<=i}+nums[i]; // 以下简写为rM
解释:当抢劫 前i个房子时,最大钱数为抢0个到前i-2个的最大值加上抢劫当前房子的钱。
比如[2,1,1,2 ,3] ;
抢第1个房子时,最大钱数0+2;rM=[2];
抢第2个房子时,最大钱数为0+1;rM=[2,1];// 前两个是base case
抢前3个房子时,最大钱数为max([2])+1;rM=[2,1,3];
抢前4个房子时,最大钱数为max([2,1])+2=4; rM=[2,1,3,4];
抢前5个房子时,最大钱数为Max([2,1,3])+3=6; rM=[2,1,3,4,6];
这种方式思考最容易想到但想要时间复杂度为O(n),必须再开一个数组维护前i-2个rM的最大值 空间不够优化
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
if(n==0){
return 0;
}
if(n==1){
return nums[0];
}
vector<int> rM(n),maxbefore(n);
dp[0]=nums[0],dp[1]=nums[1];
maxbefore[0]=nums[0];
maxbefore[1]=max(nums[0],nums[1]);
for(int i=2;i<n;++i){
rM[i]=maxbefore[i-2]+nums[i];
maxbefore[i]=max(rM[i-1],rM[i]);
}
return maxbefore[n-1];
}
};
- rM[i]=max(rM[i-2]+nums[i],rM[i-1]);
解释:对与第i个房子,有两种选择(a)抢,(b)不抢
如果选a,接下来就只能抢劫前i-2个房子 钱数为让rM[i-2]+nums[i];
如果选b,抢劫前i-1个房子 钱数为rM[i-1];
选其中的较大者即为所得
这种写法rM为第一种的maxbefore;所以可以看到第一种没有第二种好
这里给出带memo(rM)的写法 自底向上的写法直接修改上一个就好了
一直都觉得带memo的更好理解
代码来自leetcode198-Discuss-heroes3001
int[] memo;
public int rob(int[] nums) {
memo = new int[nums.length + 1];
Arrays.fill(memo, -1);
return rob(nums, nums.length - 1);
}
private int rob(int[] nums, int i) {
if (i < 0) {
return 0;
}
if (memo[i] >= 0) {
return memo[i];
}
int result = Math.max(rob(nums, i - 2) + nums[i], rob(nums, i - 1));
memo[i] = result;
return result;
}