740. Delete and Earn删除和赚取 Java

给定一个整数数组nums。您希望通过多次执行以下操作来最大化获得的分数:
选择任何nums[i]并删除它以获得nums[i]积分。之后,您必须删除每个等于 的元素nums[i] - 1和每个等于 的元素nums[i] + 1。
通过多次应用上述操作返回您可以获得的最大积分数。

示例 1:
输入: nums = [3,4,2]
输出: 6
解释:您可以执行以下操作:

  • 删除 4 获得 4 分。因此,3 也被删除。数字 = [2]。
  • 删除 2 获得 2 分。数字 = []。
    您总共获得 6 分。
    示例 2:
    输入: nums = [2,2,3,3,3,4]
    输出: 9
    解释:您可以执行以下操作:
  • 删除一个 3 获得 3 分。所有 2 和 4 也被删除。数字 = [3,3]。
  • 再次删除 3 即可获得 3 分。数字 = [3]。
  • 再次删除 3 以获得 3 分。数字 = []。
    您总共获得 9 分。

约束:
1 <= nums.length <= 2 * 104
1 <= nums[i] <= 10^4

方法1

运用之前198, 213抢钱的题思路

  1. 建立一个长度为10001的数组, 因为约束nums中的数在1到10000之间。数组用来记录当前位置有多少个数,例如[2,2,2,3,3,4], 则产生数组为[0,0,3,2,1]因为位置2在nums中的2有3个, 3有2个, 4有1个
  2. 初始化一个长度10001, 全为-1的数组
  3. 建立一个函数用来将累积求和的数添加到全为-1的数组中, 这里用到之前抢劫的思路, 当前的只能和隔一位的数加和
class Solution {
    public int deleteAndEarn(int[] nums) {
        int[] n = new int[10001];
        for (int i : nums) {
            n[i] += i;
        }
        return rob(n);
    }

    static int rob(int[] nums) {
        int temp[] = new int[nums.length];
        Arrays.fill(temp, -1);
        return helper(nums, 0, temp);
    }

    static int helper(int[] nums, int index, int[] temp) {
        if(index>=nums.length) return 0;
        if(temp[index]!=-1) return temp[index];
        return temp[index] = Math.max(helper(nums, index + 2, temp) + nums[index], helper(nums, index + 1, temp));
    }
}

由于初始化两个10000长度数组并且又把他们遍历了一遍最后, 所以时间和空间复杂度都很大

方法2

用动态规划Dynamic Programming

  1. 初始化长度10001的数组, 用来记录每个数出现的次数
  2. 定义3个变量用来存储当前值cur, 删掉的值del, 前一位的值pre
  3. 遍历这个长度为10001的数组, 这里可以将条件限制为只有里面的值大于1时才进行下面运算
for(int i=0;i<10001;i++)if(n[i]>0){...}
  1. 定一个temp用来存储当前最大值Math.max(cur,del) del指的是当前数的前一个数
  2. 如果当前数的前一位和pre不是一个, 即计数的时候为0, 例如nums=[1,1,2,2,4] count=[0,2,2,0,1], 当i=4时, i-1=3 pre=2
cur=i*count[i]+temp; //i*count[i]表示当前这个数在原数组中有多少个
del=temp;//del用来算i+1时用
  1. 当i-1=pre时cur=i*count[i]+del
class Solution {
    public int deleteAndEarn(int[] nums) {
        int[] n = new int[10001];
        for (int i : nums) {
            n[i]++;
        }
        int pre=-1,cur=0,del=0;
        for (int i = 0; i <= 10000; i++){
            if(n[i]>0){
                int temp = Math.max(cur, del);
                if (i - 1 != pre) {
                    cur = i * n[i] + temp;
                    del = temp;
                }else{
                    cur = i * n[i] + del;
                    del = temp;
                }
                pre = i;
            }
        }
        return Math.max(cur,del);
    }
}

时间复杂度O(nlogn)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值