[LeetCode] 740. Delete and Earn

You are given an integer array nums. You want to maximize the number of points you get by performing the following operation any number of times:

  • Pick any nums[i] and delete it to earn nums[i] points. Afterwards, you must delete every element equal to nums[i] - 1 and every element equal to nums[i] + 1.

Return the maximum number of points you can earn by applying the above operation some number of times.

Example 1:

Input: nums = [3,4,2]
Output: 6
Explanation: You can perform the following operations:
- Delete 4 to earn 4 points. Consequently, 3 is also deleted. nums = [2].
- Delete 2 to earn 2 points. nums = [].
You earn a total of 6 points.

Example 2:

Input: nums = [2,2,3,3,3,4]
Output: 9
Explanation: You can perform the following operations:
- Delete a 3 to earn 3 points. All 2's and 4's are also deleted. nums = [3,3].
- Delete a 3 again to earn 3 points. nums = [3].
- Delete a 3 once more to earn 3 points. nums = [].
You earn a total of 9 points.

Constraints:

  • 1 <= nums.length <= 2 * 104
  • 1 <= nums[i] <= 104

删除并获得点数。

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

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/delete-and-earn
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这道题很像198题 house robber,思路是动态规划。这里我引用一个我看到的很好的思路。根据题意,对于任何一个 nums[i] 而言,如果你选择了它,那么 nums[i - 1] 和 nums[i + 1] 都不能选且只能被直接删除,这个题设很像 house robber。获得点数的规则是如果你删除 nums[i],那么你获得的点数是 nums[i]。如果我们将数组排好序从前往后处理,其实只需要考虑当前数字之前一个数字。所以我们首先用一个 count 数组记录一下每个数字的出现次数和出现数字的最大值。接着我们再创建一个二维的 DP 数组,记录每个数字选和不选的DP值。

对于当前的数字 i,

  • 如果我选择删除 i,我的收益是不删除前一个数字 dp[i - 1][0] 获得的收益 + 删除当前数字的收益 i * counts[i]
  • 如果我选择不删除 i,我的收益是删除和不删除前一个数字的收益的较大值

最后返回最后一个数字的DP值。

时间O(n)

空间O(n^2)

Java实现

 1 class Solution {
 2     public int deleteAndEarn(int[] nums) {
 3         int[] counts = new int[10001];
 4         int max = 0;
 5         for (int num : nums) {
 6             counts[num]++;
 7             max = Math.max(max, num);
 8         }
 9 
10         int[][] dp = new int[max + 1][2];
11         for (int i = 1; i <= max; i++) {
12             dp[i][1] = dp[i - 1][0] + i * counts[i];
13             dp[i][0] = Math.max(dp[i - 1][1], dp[i - 1][0]);
14         }
15         return Math.max(dp[max][0], dp[max][1]);
16     }
17 }

 

我这里提供另一种做法,思路也是DP,代码写的跟 house robber 很像。初始值是 first 和 second,first 是删除第一个元素的收益(偷第一个房子的收益),second 是不删除第一个元素删除第二个元素的收益(不偷第一个房子但是偷第二个房子的收益)。这里我们首先需要用一个数组 sum 记录偷每一个房子的收益。

时间O(n)

空间O(n)

Java实现

 1 class Solution {
 2     public int deleteAndEarn(int[] nums) {
 3         int max = 0;
 4         for (int num : nums) {
 5             max = Math.max(max, num);
 6         }
 7 
 8         // sum数组记录的是相同元素之和,比如有4个2的话,sum[2] = 8
 9         int[] sum = new int[max + 1];
10         for (int num : nums) {
11             sum[num] += num;
12         }
13         return rob(sum);
14     }
15 
16     public int rob(int[] nums) {
17         int len = nums.length;
18         int first = nums[0];
19         int second = Math.max(nums[0], nums[1]);
20         for (int i = 2; i < len; i++) {
21             int temp = second;
22             second = Math.max(first + nums[i], second);
23             first = temp;
24         }
25         return second;
26     }
27 }

 

相关题目

198. House Robber

740. Delete and Earn

LeetCode 题目总结

posted @ 2022-03-05 14:53  CNoodle  阅读(137)  评论(0编辑  收藏  举报