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].
给出一个数组,删除一个数字后要同时删除比它大1和小1的数字,然后积这个删除掉的数字的分,问最后最多能积多少分。
思路:
可以把相同的数字全都堆到一起,因为删掉一个数字要同时删掉所有的左右相邻数字,所以不用管数字有多少个,直接堆在一起全部删除就行了。既然左右已经删除掉了,下次再选这个数字就不会再有影响,所以每次可以直接把堆在一起的数字的和加起来。
另外,说是删除左右相邻的数字,其实不用删除,只要不能访问就行了。那么问题就转化为,访问第 i 个数字,就不能访问它的左右邻居。
那么问题再次转化为198. house robber,抢一个house的money,就不能抢这个house的相邻的house
所以,第一步,堆数字,第二步,house robber
第二步的dp[n] = max(dp[n-2] + nums[i], dp[n-1]), 因为只用到前两位的dp,所以不用数组,只用dp1和dp2两个数字保存
public int deleteAndEarn(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
int maxE = 0;
for(int i = 0; i < n; i++) {
maxE = Math.max(maxE, nums[i]);
}
int[] points = new int[maxE + 1];
for(int i = 0; i < n; i++) {
points[nums[i]] += nums[i];
}
int dp2 = points[0];
int dp1 = points[1];
for(int i = 2; i <= maxE; i ++) {
int dp = Math.max(dp2 + points[i], dp1);
dp2 = dp1;
dp1 = dp;
}
return dp1;
}