【第十五周】740. Delete and Earn
2017-12-20 17:54
453 查看
原题
Given an array nums of integers, you can perform operations on the array. In each operation, you pick any nums[i] and delete it to earn nums[i] points. After, you must delete every element equal to nums[i] - 1 or nums[i] + 1. You start with 0 points. Return the maximum number of points you can earn by applying such operations. Example 1: Input: nums = [3, 4, 2] Output: 6 Explanation: Delete 4 to earn 4 points, consequently 3 is also deleted. Then, delete 2 to earn 2 points. 6 total points are earned. Example 2: Input: nums = [2, 2, 3, 3, 3, 4] Output: 9 Explanation: Delete 3 to earn 3 points, deleting both 2's and the 4. Then, delete 3 again to earn 3 points, and 3 again to earn 3 points.9 total points are earned. Note: The length of nums is at most 20000. Each element nums[i] is an integer in the range [1, 10000].
leetCode地址:https://leetcode.com/problems/delete-and-earn/description/
解题思路
题目大意:有一组数,每个值的范围为[1,10000]。每次可以从数组中选择一个值t,所有的t都会从数组中删去,同时也要删去所有值为t+1与t-1的数。假设这次操作删去了n个t,就可以获得n*t分。现在求将数组完全删除,所能获得的最高分。
这种题目很明显可以使用动态规划来求解,不过如何定义状态是一个重点。
一开始我的思路是这样的:先将数组排序,然后删去所有完全不连续的值(完全不连续的x, 即数组中没有x+1与x-1),这一阶段删去的数都是我们获得的分数;然后剩下的数都是部分连续的,即删去某个数肯定会丢掉其邻居的分数。然后我们对每一个部分连续的数串,都进行动态规划求解,获取到每一个数串的最高分数。
我们将部分连续数串求最高分的问题分离出来,抽象成另一个问题:有一个数组arr[],每相邻的两个数中最多选择1个,求被选择数的最大和。这个问题的动态规划求解思路: 定义状态F(k)为arr[0]到arr[k]的最大和, 状态转移方程:
F(k+1) = max( F(k-1) + arr[k+1], F(k) )。这样子问题就解决了。
后来我发现,这样的算法处理还是太麻烦了;而且题目中有一个条件: Each element nums[i] is an integer in the range [1, 10000]. 所有数的取值范围为1-10000;而10000并不是一个非常大的数字——所以我们可以将排序后的数列看成完全连续的,而不用将孤立的数分开处理。具体如何实现呢?对于那些没有邻居的数,都可以看成左右都有邻居“0”,再对整体使用动态规划算法,就能够除去很多不必要的步骤了。因为很明显,为一个数添加邻居“0”对结果肯定是没有影响的,删去这个数,获得的分数还是一样的。
这时我们算法的复杂度是多少呢?排序算法一般为O(nlogn),动态规划算法复杂度为O(n),所以总复杂度为O(nlogn)。还能不能更简化一点呢?我们发现,既然每个数的取值范围为1-10000,那就完全可以使用另外一个排序思路“桶排序”。桶排序的复杂度为O(n);所以总复杂度就降成了O(n)。
代码
class Solution { public: int deleteAndEarn(vector<int>& nums) { if (nums.size() == 0) return 0; int bucket[10001]; memset(bucket, 0, sizeof(bucket)); for (int i : nums) bucket[i]++; int dp[10001]; memset(dp, 0, sizeof(dp)); dp[1] = bucket[1]; dp[2] = max(dp[1], bucket[2]*2); for (int i = 3; i <= 10000; i++) { dp[i] = max(dp[i-2] + bucket[i]*i, dp[i-1]); } return dp[10000]; } };
总结
1、动态规划2、排序算法
相关文章推荐
- 740. Delete and Earn
- 740. Delete and Earn
- 740. Delete and Earn
- Leetcode刷题:740. Delete and Earn
- 740. Delete and Earn
- 740. Delete and Earn
- 740. Delete and Earn
- 740. Delete and Earn
- LWC 61:740. Delete and Earn
- 740. Delete and Earn
- 740[Medium]:Delete and Earn
- Delete and Earn
- LeetCode | 740. Delete and Earn
- 740. Delete and Earn
- week17-leetcode #740-DeleteandEarn
- [LeetCode] Delete and Earn 删除与赚取
- Leetcode 740. Delete and Earn
- Delete and Earn
- [LeetCode]740. Delete and Earn
- [leetcode] 740. Delete and Earn