740. 删除并获得点数(Java)
题目链接:https://leetcode-cn.com/problems/delete-and-earn
难度:中等
1.题目
给你一个整数数组 nums ,你可以对它进行一些操作。
每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除每个等于 nums[i] - 1 或 nums[i] + 1 的元素。
开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。
2.示例
输入:nums = [2,2,3,3,3,4]
输出:9
解释:删除 3 获得 3 个点数,接着要删除两个 2 和 4 。
之后,再次删除 3 获得 3 个点数,再次删除 3 获得 3 个点数。
总共获得 9 个点数。
3.题解
思路:对于求最值的问题,一般使用动态规划解决。在取任意一个数的时候,我们应该尽可能多的将所有相同的数都取出来,这样有利于我们计算最大和。由于对于nums数组我们并不知道其中相同元素的个数,所以我们可以建一个新数组count来存储在对应下标下的数在nums中的个数。其长度等于nums数值中的最大值+1。
对此,我们设f[i]表示在最大值为i时,数组能获得的最大点数。则f[i] = Max{f[i-2]+count[i]*i,f[i-1]}(i>2)。
class Solution {
public int deleteAndEarn(int[] nums) {
int n = nums.length;
int maxVal=0;
//循环获取最大值
for(int i=0;i<n;i++){
maxVal=maxVal<nums[i]?nums[i]:maxVal;
}
int[] count = new int[maxVal+1];
//将数组nums中的数填入对应下标的count数组
for(int i=0;i<n;i++){
count[nums[i]]++;
}
return dp(count);
}
public int dp(int[] count){
int n = count.length;
int[] f = new int[n];
//满足方程的数组i>2,则我们需要考虑在i<=2时的特殊情况
f[1] = count[1]*1;
if(n>2) f[2] = Math.max(f[1],count[2]*2);
for(int i=3;i<n;i++){
f[i] = 0;
f[i] = Math.max(f[i-2]+count[i]*i,f[i-1]);
}
return f[n-1];
}
}
复杂度分析
时间复杂度:O(N+M)
空间复杂度:O(M)
N表示数组nums的长度,M表示数组中元素的最大值。
4.总结
对于动态规划问题,需要先考虑转换方程,在考虑特殊情况。编写代码时思路就会清晰许多。