leetcode 740. 删除与获得点数 —— 动态规划

740. 删除与获得点数

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

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

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

示例 1:

输入: nums = [3, 4, 2]
输出: 6
解释: 
删除 4 来获得 4 个点数,因此 3 也被删除。
之后,删除 2 来获得 2 个点数。总共获得 6 个点数。

示例 2:

输入: nums = [2, 2, 3, 3, 3, 4]
输出: 9
解释: 
删除 3 来获得 3 个点数,接着要删除两个 2 和 4 。
之后,再次删除 3 获得 3 个点数,再次删除 3 获得 3 个点数。
总共获得 9 个点数。

注意:
nums的长度最大为20000。
每个整数nums[i]的大小都在[1, 10000]范围内。

题目来源:力扣(LeetCode)
https://leetcode-cn.com/problems/delete-and-earn

解题思路:

题目要求是选择数组中某个元素值删除,并且比这个元素值小1或大1的元素也要被删除,不区分元素值在数组中的位置,得到的点数是选中元素的的值,而附带删除的其他元素没有点数。

既然不区分元素中的位置,只在乎元素值的大小,可以先遍历数组将所有元素值按照从小到达的顺序放入到一个新的数组 count,并且新数组的索引为原数组中元素值,新数组中元素的值为对应索引在原数组中所有点数和。那么原数组问题就变成新数组的问题。

接下来遍历新数组 count,现在需要找到对应的最优递推关系式。我们假设将遍历过的元素构成一个子数组(自己),每遍历一个新元素 n 就加入子数组后面,设加入新元素后的新子数组(儿子)的点数最大为 dp[n],则这个新加入的元素是否参与新子数组的点数计算,可以得到两种可能,即作为选择删除项加入点数累积;或者不作为选中删除项就不加累积。
若不作为选中删除项,则新的子数组(儿子)的点数还是为原子数组(自己)(n-1个元素)的点数,dp[n] = dp[n-1];
若作为选中删除项,则其左边相邻的第一个元素就不能参与点数累积,则新的子数组的点数为原子数组(父亲)(n-2个元素)的点数加上新增元素的点数,dp[n] = dp[n-2] + count[n]。

最优递推关系式为:
dp[n] = max{dp[n-1], dp[n-2] + count[n]}。

子问题的解会多次使用,所以使用动态规划求解。

代码:

// 动态规划
public int deleteAndEarn(int[] nums) {
    if (nums == null && nums.length == 0){
        return 0;
    }
    // 定义一个数组count,count索引表示 nums 数组中元素的值,count 的值表示 nums 中元素值的点数。
    int[] count = new int[10001];
    for (int i = 0; i < nums.length; i++) {
        count[nums[i]] += nums[i];
    }
    // 记录count前n个元素组成的数组的最大点数dp[n]。
    // 前 n 个元素促成的数组的最大点数有两种情况并取最大,第 n 个元素为构成部分之一或不参与构成。
    // 即 dp[n] = Math.max(dp[n-2]+count[n],dp[n-1])
    int[] dp = new int[10001];
    dp[0]= count[0];
    dp[1] = count[1];
    // 遍历数组count[];
    for (int n = 2; n < count.length; n++) {
        // 记录遍历过的子数组的最大点数,i 为当前子数组的最后一个。
        // 该数组可得到的最大点数存在最后一个删除与不删除两种情况中。
        dp[n] = Math.max(dp[n-2]+count[n],dp[n-1]);
    }
    return dp[10000];
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值