leetcode 740删除并获得点数

题意

给你一个整数数组 nums ,你可以对它进行一些操作。

每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除每个等于 nums[i] - 1 或 nums[i] + 1 的元素。

开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数

题解

数组元素可重复,对于重复的元素来说,要么都选要么都没被选(因为想要最大点数,能选肯定都会选,没被选意味着我们选择了前后的值,这个元素被剔除了)。因为如果选择了其中一个元素a,那么a-1,a+1都会被剔除,那么剩下的a必然可以被选择以增加点数。如果a没有被选择,或者说我们选择了a-1或者a+1,这样所有的a就会被剔除。所以可以用sum[]数组记录所有相同元素的和,那么a如果被选择,点数将增加sum[a].

问题转化成如下:

给你一组整数数组sum[],选择其中一部分元素,使得和最大,选择的原则是当选择了sum[i]时,sum[i-1]和sum[i+1]不可被选择。
这和leetcode打家劫舍问题一模一样。方程为
dp[i] = max(dp[i-1],dp[i-2]+sum[i])

一开始做打家劫舍问题时,我很不能理解dp[i]的求解是怎么影响第i+1个元素是否取的。换句话说,dp[i]的求解我们不知道第i个元素是否被取了,如果被取了,那么第i+1个元素必然不能被取。

其实解释很简单,dp[i]没有影响第i+1个元素,第i+1个元素的合法取法是在遍历到i+1时决定的。遍历到i+1时,我们可以选择取或不取,如果取那么第i个元素不能被取,因此状态从dp[i-1]转移而来,不管dp[i]是如何计算出来的,i有没有被取,dp[i]这个状态都不可用。为什么,如果dp[i]是取了i的,那正好我们不需要该状态,如果没取i,那也是正好的。如果不取i+1,那么i可以被取,状态从dp[i]转移而来。此时dp[i]如何计算而来,有没有取i也不重要。如果取了i,因为i+1没有取,所以合法。如果没有取i,同样也合法。

为什么只有这两种方案呢,因为不管最终方案如何,那么对于当前状态的最后一个元素i+1,在最终方案里只有两个选择,在或不在。在,那么上一状态是dp[i-1],不在上一状态是dp[i]。
举个例子解释一下:
现在1,2,3已经知道了dp[1] dp[2] dp[3],那么求dp[4]该怎么求。很明显有这么几种方法,1,3或者2,4或者1,4,按照4是否取,可以分成2,4和1,4这一种情况和1,3这一种情况。4没有取那就直接是dp[3],因为3有可能取有可能不取。4取了就是dp[2]+nums[4]。即便dp[3]的3没有取,3没有取dp[3]就退化成dp[2]了,这种情况被考虑在4取了之中。
所以代码很简单了:

class Solution {
private:
    int rob(vector<int> &nums) {
        int size = nums.size();
        int first = nums[0], second = max(nums[0], nums[1]);//first记住dp[i-2],second记住dp[i-1]
        for (int i = 2; i < size; i++) {
            int temp = second;
            second = max(first + nums[i], second);
            first = temp;
        }
        return second;
    }

public:
    int deleteAndEarn(vector<int> &nums) {
        int maxval = 0;
        for (int val : nums) {//找出元素最大值
            maxval = max(maxval, val);
        }
        vector<int> sum(maxval + 1);
        for (int val : nums) {//求解sum数组
            sum[val] += val;
        }
        return rob(sum);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值