题目
思路
为了获取最多的点数,对于数组nums
中的数字n
,只存在所有的数字n
均被记为点数(选择了数字n
)和所有的数字n
均没有被记为点数的情况(选择了数字n+1
或者n-1
使得所有n
均被删除),即不存在只选择部分数字n
的情况。
根据上述分析,本题目可以转化为从存在一些各不相同的数字,每个数字对应一个分数,当选择了数字n
就不能选择数字n+1
和n-1
,求所有可能选择方案得到的分数中的最大分数。
设最大的数字为n
, 我们从n
开始考虑, 如果我们选择该数字,则需要从所有数字中去掉n, n-1, n+1
,由于n
是最大的数字,因此仅需要去掉n,n-1
,然后求剩余数字最大分数(问题规模减小);如果我们不选择,则需要从所有数字中去掉n
,然后求剩余数字的最大分数(问题规模减小),最后再比较这两中选择,取分数较大的一个则得到最终结果。
根据上述分析,我们要求<=n
的所有数字的最大分数(最终结果),可以利用<=n-1
的数字的最大分数和<=n-2
的数字的最大分数来求。我们使用数组dp[n]
来表示<=n
的所有数字的最大分数,则有
dp[n] = max(dp[n-1], dp[n-2] + sum[n])
显然dp[1] = sum[1]
, 由于某些数字在题目给出的数组中不存在,我们将这些数字对应的分数设置为0即可。从0迭代到n
即可得到最终结果(数字从1开始,为了方便编程,可以将所有数字-1
,使其从0
开始)。
代码
class Solution {
public:
int deleteAndEarn(vector<int>& nums) {
int max_val =0;
// 搜索最大的数字
for(int i : nums) {
if (i > max_val) {
max_val = i;
}
}
// 计算每种数字总点数和(vector自动初始化为0),
// 因此原数组中不存在的数对应点数为0
vector<int> sum(max_val);
for(int i : nums) {
// 将所有数字-1,方便存储
sum[i-1] += i;
}
vector<int> dp(max_val);
dp[0] = sum[0];
for(int i=1; i<dp.size(); i++) {
int max_a, max_b;
// 选择当前数字
max_a = sum[i];
if (i > 1) {
max_a += dp[i-2];
}
// 不选择当前数字
max_b = dp[i-1];
dp[i] = max(max_a, max_b);
}
return dp[max_val - 1];
}
};