两题的思路相似,均使用动态规划来解题。
198. 打家劫舍
题目:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/house-robber
解题思路:
创建数组dp[],dp[i]的含义表示为顺序偷窃到第 i 号房屋时能偷窃到的最高金额,那么对于所有房屋偷窃得到的最高金额就是 dp[nums.size()]。
对于dp[i] (即偷到第 i 号房屋的最高金额),要么为dp[i-1],要么选择偷窃 i-2 号房屋和第 i 号房屋,则dp[i] 就是选取其中的较大值:dp[i]=max(dp[i-1],dp[i-2]+nums[i]).
代码:
class Solution {
public:
int rob(vector<int>& nums) {
vector<int> dp;
dp.push_back(0); //这里插入0 避免边界条件:只有一个房屋
dp.push_back(nums[0]);
for(int i=1;i<nums.size();i++){
dp.push_back(max(dp[i],nums[i]+dp[i-1]));
}
return dp[dp.size()-1];
}
};
740. 删除并获得点数
题目:
给你一个整数数组 nums ,你可以对它进行一些操作。
每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除 所有 等于 nums[i] - 1 和 nums[i] + 1 的元素。
开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/delete-and-earn
解题思路:
其实本题和上题一致的,将nums数组进行排序,在对排序后的nums扫描过程中,创建一个数组dp[],用于存储nums的数字(互不相同),并且创建一个hash表存储每个数组对应的个数,这样其实就是上题了。
对dp[]数组的顺序判断,如果dp[i+1]==pre+1,那么就需要进行比较dp[i+1]=max(dp[i],dp[i-1]+dp[i+1]*hash[dp[i+1]]);如果dp[i+1]!=pre+1,那么dp[i+1]=dp[i]+dp[i]*hash[dp[i]]。
代码:
class Solution {
public:
int deleteAndEarn(vector<int>& nums) {
unordered_map<int,int> Num;
sort(nums.begin(),nums.end());
vector<int> dp;
dp.push_back(0);
Num[0]=1;
for(int i=0;i<nums.size();i++){
Num[nums[i]]++;// 记录每一个数字有几个
if(nums[i]!=dp.back())
dp.push_back(nums[i]); //将数字添加到dp中
}
int pre=dp[1];
dp[1]=dp[1]*Num[dp[1]];
for(int i=2;i<dp.size();i++){
if(dp[i]-pre==1){ //要和pre比较 而不能是dp[i-1]因为dp变化了
pre=dp[i];
dp[i]=max(dp[i-1],dp[i]*Num[dp[i]]+dp[i-2]);
}
else{
pre=dp[i];
dp[i]=dp[i-1]+dp[i]*Num[dp[i]];
}
}
return dp[dp.size()-1];
}
};