题目描述
给你一个整数数组 n u m s nums nums ,你可以对它进行一些操作。
每次操作中,选择任意一个 n u m s i numsi numsi,删除它并获得 n u m s i numsi numsi 的点数。之后,你必须删除 所有 等于 n u m s i − 1 numsi - 1 numsi−1 和 n u m s i + 1 numsi + 1 numsi+1 的元素。
开始你拥有 0 0 0 个点数。返回你能通过这些操作获得的最大点数。
示例 1 :
输入 :nums = 3,4,2
输出 :6
解释:
- 删除 4 获得 4 个点数,因此 3 也被删除。nums = 2
- 之后,删除 2 获得 2 个点数。nums = \[\]
- 总共获得 6 个点数。
示例 2 :
输入 :nums = 2,2,3,3,3,4
输出 :9
解释:
- 删除 3 获得 3 个点数。所有的 2 和 4 也被删除。nums = 3,3
- 之后,再次删除 3 获得 3 个点数。nums = 3
- 再次删除 3 获得 3 个点数。nums = \[\]
- 总共获得 9 个点数
算法原理
根据题目描述,如果在 n u m s nums nums 中选择了 n u m s i numsi numsi,那 n u m s i − 1 numsi - 1 numsi−1 和 n u m s i + 1 numsi + 1 numsi+1 就不能选。假设 n u m s = 1 , 2 , 3 , 4 , 5 nums = 1, 2, 3, 4, 5 nums=1,2,3,4,5,刚开始选择 1 1 1,就无法选择相邻的 2 2 2,接下来选择 3 3 3,就无法选择相邻的 4 4 4。这和 打家劫舍 I 是类似的。但是假设 n u m s = 1 , 1 , 2 , 2 , 4 , 4 , 5 , 7 nums = 1, 1, 2, 2, 4, 4, 5, 7 nums=1,1,2,2,4,4,5,7,由于数字不连续,选了 2 2 2 以后,相邻的数字 4 4 4 还是可以选的,因此可以创建一个数组 a r r arr arr, a r r n u m s \[ i ] arrnums\[i] arrnums\[i] 保存的是 n u m s nums nums 中所有 n u m s i numsi numsi 之和,代入上面的 n u m s nums nums 中就后, a r r arr arr 的样子就是:

由于下标是连续的,所以能够转化为 打家劫舍 I
具体做法为:
先求出 n u m s nums nums 中,相同 n u m s i numsi numsi 的和,填入 a r r n u m s \[ i ] arrnums\[i] arrnums\[i],然后做一次 打家劫舍 I
创建两个数组 f f f 和 g g g,确定状态表示: f i fi fi 表示选择了 a r r i arri arri 之后的最大点数, g i gi gi 表示没选择 a r r i arri arri 时的最大点数
确定状态转移方程: f i fi fi 要选择 a r r i arri arri,所以 a r r i − 1 arri-1 arri−1 不选, f i fi fi 就等于不选 a r r i − 1 arri-1 arri−1 时的最大点数加上 a r r i arri arri,也就是 f i = g i − 1 + a r r i fi = gi - 1 + arri fi=gi−1+arri。 g i gi gi 不选 a r r i arri arri,所以 a r r i − 1 arri-1 arri−1 可选不选,选择了 a r r i − 1 arri-1 arri−1, g i gi gi 就等于选了 a r r i − 1 arri-1 arri−1 时的最大点数,就是 f i − 1 fi-1 fi−1。不选择 a r r i − 1 arri-1 arri−1, g i gi gi 就等于不选 a r r i − 1 arri-1 arri−1 时的最大点数,就是 g i − 1 gi-1 gi−1, g i = g i − 1 gi = gi-1 gi=gi−1。所以 g i = m a x ( f i − 1 , g i − 1 ) gi = max(fi-1, gi-1) gi=max(fi−1,gi−1)
初始化:根据状态转移方程, 0 0 0 下标填的时候会越界,所以初始化 f 0 f0 f0 和 g 0 g0 g0,根据状态表示, f 0 = a r r 0 f0 = arr0 f0=arr0, g 0 = 0 g0 = 0 g0=0
填表顺序:从左向右,两个一起填
返回值:要选到最后一个位置,最后一个位置可选可不选,所以是 m a x ( f n − 1 , g n − 1 ) max(fn - 1, gn - 1) max(fn−1,gn−1)
代码
cpp
class Solution {
public:
int deleteAndEarn(vector<int>& nums)
{
int n = nums.size();
int m = *max_element(nums.begin(), nums.end());
vector<int> arr(m + 1, 0);
for (int i = 0;i < n;++i)
arr[nums[i]] += nums[i];
vector<int> f(m + 1, 0);
vector<int> g(m + 1, 0);
f[0] = arr[0];
g[0] = 0;
for (int i = 1;i <= m;++i)
{
f[i] = g[i - 1] + arr[i];
g[i] = max(f[i - 1], g[i - 1]);
}
return max(f[m], g[m]);
}
};