题目: 198. 打家劫舍
标签:数组 动态规划
题目信息:
思路一:
这道题就是到动态规划题,动态规划题有个特性,不过我现在还没领悟明白。
不过好在我知道做动态规划题的套路。
第一步: 确定dp数组及其下标含义
这里我们的dp数组下标含义大概就为偷到第i家时的最大收获。
第二步:确定递推公式
由题目信息可知,小偷在第i家时,有两种情况:
1,前面一家偷了。2,前面一家没偷。
如果是第一种情况,偷了前面一家就不能偷这家了,不然会被抓。
如果是第二种情况,没偷前面一家那就偷这家,
所以可以得到dp[i] = max(dp[i-1],dp[i-2]+nums[i])
第三步:初始化dp数组
首先新建dp数组,里面的值全为0。
由递推公式可以得知,有i-2的存在,所以就要先初始化两项,分别是dp[0]和dp[1]。
第四步:遍历,生成dp数组
这一步就是遍历,按递推公式来生成dp数组了。
第五步:
print dp数组,看看对不对,结束。
代码实现:
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
if(n==0){
return 0;
}else if(n==1){
return nums[0];
}
//1. 确定dp数组含义
vector<int>dp(n,0);//偷到第i家时的最大钱数
//2. 确定递推公式
//如题,每家只能偷一次,不能偷相邻的,
//那么dp[i]要么是dp[i-1],要么是dp[i-2]+nums[i]
//所以,dp[i] = max(dp[i-1],dp[i-2]+nums[i]);
//3. 遍历初始化dp数组
//既然dp[i]是由dp[i-1],dp[i-2]而来,那么dp[0],dp[1]就都要有初始化值才行
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(int i=2;i<n;i++){
dp[i] = max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[n-1];
}
};
没注释的代码:
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
if(n==0){
return 0;
}else if(n==1){
return nums[0];
}
vector<int>dp(n,0);
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(int i=2;i<n;i++){
dp[i] = max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[n-1];
}
};
时间复杂度分析:
一层for循环,O(n)
总结:
dp五步法:
第一步: 确定dp数组及其下标含义
第二步:确定递推公式
第三步:初始化dp数组
第四步:遍历,生成dp数组
第五步:print dp数组,看看对不对,结束。