LeetCode_740 删除并获得点数(动态规划)

博客探讨了如何使用动态规划优化LeetCode 740题目的解决方案,从最初的二维数组和普通动态规划,逐步简化到一维数组和仅使用两个变量的状态转移,降低了时间和空间复杂度。通过维护一个sum数组记录每个数字出现的总和,实现了高效解法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来源:LeetCode_740 删除并获得点数
在这里插入图片描述
第一眼看到这个题目的确就会想到打家劫舍问题,隔壁的屋子不能连续偷。
就想着拿二维数组记录数字和他对应出现的次数。然后动态转移方程就是
dp[n] = dp[n-1] + 对应的数字数量 (nums[n] != nums[n-1]+1)
max{dp[n-2]+对应的数字
数量, dp[n-1]}.

public int deleteAndEarn(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for(int i = 0; i<nums.length;i++){
            set.add(nums[i]);
        }
        int n = set.size();
        int[][] data = new int[n][2];
        Arrays.sort(nums);
        data[0][0] = nums[0];
        data[0][1] = 1;
        int index = 0;
        for (int i = 1; i < nums.length;i++){
             if (nums[i]!=nums[i-1]){
                 data[++index][0] = nums[i];
                 data[index][1] = 1;
             }else{
                 data[index][1] += 1;
           }
        }
          int[] dp = new int[n+1];
          dp[1] = data[0][0] * data[0][1];
          for(int i = 2; i <= n; i++ ){
              if(data[i-1][0]!=data[i-2][0]+1){
                  dp[i] = dp[i-1] + data[i-1][0] * data[i-1][1];
              }else{
                  dp[i] = Math.max(dp[i-2] + data[i-1][0] * data[i-1][1], dp[i-1]);
              }
          }
          return dp[n];
    }

发现时间复杂度太高了直接简化一下,用一个sum数组表示sum[x] = x * x在nums中出现的次数。
再进行动态规划

public int deleteAndEarn(int[] nums) {
        int maxValue = 0;
        // 得到nums数组中的最大数
        for(int i : nums){
            maxValue = Math.max(maxValue, i);
        }
        int[] sum = new int[maxValue + 1]; // sum数组里面存储的数为sum[x] 为 x*nums中x的数量;
        for(int i : nums){
            sum[i] += i;
        }
        //然后用动态规划思路(打家劫舍问题)
        int[] dp = new int[maxValue + 1];
        dp[1] = sum[1];
        for(int i = 2; i <= maxValue; i++){
            dp[i] = Math.max(dp[i-2] + sum[i], dp[i-1]);
        }
        return dp[maxValue];
    }

此时时间复杂度是降低了,但空间复杂度还有优化的空间。
在动态规划部分,我们发现i状态只和前两个状态有关系

//然后用动态规划思路(打家劫舍问题)将数组简化成两个int
        int first = 0 , secend = sum[0];
        for(int i = 1; i <= maxValue; i++){
            int temp = secend;
            secend = Math.max(first + sum[i], secend);
            first = temp;
        }
        return secend;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值