[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 earnnums[i]
points. Afterwards, you must delete every element equal tonums[i] - 1
and every element equal tonums[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 }
相关题目