Delete and Earn
跟之前的上楼梯问题有点像,其实就是一个数组nums
选中了一个数以后,它的连续的前一个或者后一个都要删掉,求可获得的最大的和。
算法过程分析:在到达一个数时,只能选择留下前一个数,或者留下前前一个数加上现在的值,用totol
记录某一个数的最大值,那么转移方程为totol[i] = max(totol[i - 1], totol[i - 2] + nums[i])
,因为还有很多重复的值,所以用了一个map
来记录有多少重复的,并且map
已经是排好序的,这一点很方便。
以下是代码:
class Solution {
public:
int deleteAndEarn(vector<int>& nums) {
if(nums.empty()) return 0;
map<int, int> m;
vector<int> totol(10010, 0);
int res = 0, last, last1;
for (int i = 0; i < nums.size(); i++) {
auto it = m.find(nums[i]);
if(it == m.end()) m[nums[i]] = 1;
else m[nums[i]] = m[nums[i]] + 1;
}
auto it = m.begin();
totol[it -> first] = it -> first * it -> second;
res = totol[it -> first];
last = last1 = it -> first;
int i = 1;
for (it++; it != m.end(); it++, i++) {
if(last1 + 1 == it -> first) {
if(i == 1) {
totol[it -> first] = max(it -> first * it -> second, totol[last]);
last1 = it -> first;
} else {
totol[it -> first] = max(totol[last1], totol[last] + it -> first * it -> second);
last = last1;
last1 = it -> first;
}
} else {
totol[it -> first] = totol[last1] + it -> first * it -> second;
last = last1;
last1 = it -> first;
}
if(res < totol[it -> first]) res = totol[it -> first];
}
return res;
}
};
这一题写的比较复杂,看到了discuss以后,发现一个非常简单的dp方法,我写的复杂是因为在考虑第一个数和第二个该怎么获取,这里变得很麻烦,discuss的方法是将其存到数组中,从第0个开始,dp[i]表示i可以获取最多的数,这里学到了一个,把数放后一个,而不是从头开始放。
下面是discuss的代码:
“`c++
int deleteAndEarn(vector& nums) {
if(nums.size()==0) return 0;
std::vector<int> a(10001,0); // frequency of numbers from 1 to 10000
for(int i:nums){
++a[i];
}
std::vector<int> dp(a.size()+1,0);
dp[1]=a[1]*1;
for(int i=2;i<=10000;++i){
dp[i]=std::max(dp[i-1],a[i]*i+dp[i-2]);
}
return dp[10000];
}
```