LeetCode刷题笔记-动态规划-day3文章目录
LeetCode刷题笔记-动态规划-day3
198. 打家劫舍
1.题目
2.解题思路
3.代码
213. 打家劫舍 II
1.题目
2.解题思路
3.代码
740. 删除并获得点数
1.题目
2.解题思路
3.代码
LeetCode刷题笔记-动态规划-day3
198. 打家劫舍
1.题目
原题链接：198. 打家劫舍
2.解题思路
我们可以用f[i]表示小偷走到第i个房间偷的总金额，可以分两种情况：
小偷不选第i个房间的现金，那么f[i]=f[i-1];
小偷选择偷第i个房间的现金，因为不能选择连续的房间，所以f[i]=f[i-2]+nums[i];
如图：
图转载：https://www.acwing.com/solution/content/19504/
3.代码
class Solution { public: int rob(vector<int>& nums) { int n=nums.size(); vector<int> f(n+1); if(n<2) return nums[0]; f[0]=nums[0],f[1]=max(nums[0],nums[1]); for(int i=2;i<n;i++){ f[i]=max(f[i-1],f[i-2]+nums[i]); } return f[n-1]; } };
213. 打家劫舍 II
1.题目
原题链接：213. 打家劫舍 II
2.解题思路
从题意可知该题相比198. 打家劫舍只是多了一个条件：第一个房间和最后一个房间不能同时选，因此我们可以枚举这两种情况：
一定不选第一个，即求出[2,n]区间可以得到的最大价值
一定不选最后一个，即求出[1,n-1]区间可以得到的最大价值
最后取两种情况的最大值即可。
3.代码
class Solution { public: int rob(vector<int>& nums) { int n=nums.size(); vector<int> f(n+1); if(n<2) return nums[0]; if(n==2) return max(nums[0],nums[1]); f[0]=nums[0],f[1]=max(nums[0],nums[1]); for(int i=2;i<n-1;i++){ f[i]=max(f[i-1],f[i-2]+nums[i]); } int t1=f[n-2]; f.clear(); f[0]=0,f[1]=nums[1]; for(int i=2;i<n;i++){ f[i]=max(f[i-1],f[i-2]+nums[i]); } int t2=f[n-1]; return max(t1,t2); } };
740. 删除并获得点数
1.题目
原题链接：740. 删除并获得点数
2.解题思路
仔细分析题目可知该题与198. 打家劫舍相似，不同的是每个元素可能有多个。
因为题目要求了如果选择num[i]，就不能选择等于 nums[i] - 1 和 nums[i] + 1 的元素，等价于198. 打家劫舍中我们不能选择连续的房间。
我们可以用map记录每个元素的个数，由题目给出的数字范围我们可以枚举1到10000的所有元素。用f[i]表示走到该点获取的最大点数，则：
f[i]=max(f[i-1],f[i-2]+i*cnt[i]);
3.代码
class Solution { public: int deleteAndEarn(vector<int>& a) { map<int,int> cnt; for(auto x:a) cnt[x]++; vector<int> f(10001); f[1]=1*cnt[1]; for(int i=2;i<10001;i++){ f[i]=max(f[i-1],f[i-2]+i*cnt[i]); } return f[10000]; } };