Leetcode 740
删除与获得点数
题目描述:给定一个整数数组 nums ,你可以对它进行一些操作。
每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除每个等于 nums[i] - 1 或 nums[i] + 1 的元素。
开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。
示例1:
输入: nums = [3, 4, 2]
输出: 6
解释:
删除 4 来获得 4 个点数,因此 3 也被删除。
之后,删除 2 来获得 2 个点数。总共获得 6 个点数。
示例2:
输入: nums = [2, 2, 3, 3, 3, 4]
输出: 9
解释:
删除 3 来获得 3 个点数,接着要删除两个 2 和 4 。
之后,再次删除 3 获得 3 个点数,再次删除 3 获得 3 个点数。
总共获得 9 个点数。
解法:动态规划
动态规划思想:我们可以从一个数开始扩展,也就是当有一个新的数加入时,点数也可以跟着增加,根据这个数与最大值的相邻关系进行分类处理
对于一个nums数组,当我们增加一个数i
时,如果i
跟nums
数组中最大的数相等或者大一位以上,那点数就是前面的点数加上i
,如果i
比nums
数组中最大的数大一位,就是相邻的情况,那么我们需要引入两个值usings,avoid
,usings
表示考虑nums
中最大的数,而avoid
表示不考虑nums
中最大的数,因此我们可以得到这样一个状态转移方程:
当i跟nums数组中最大的数相等或者大一位以上
m = max(usings,aviod)
usings = i*count[i]+m
avoid = m
当i比nums数组中最大的数大一位
m = max(usings,aviod)
usings = i*count[i]+avoid
avoid = m
第一种情况:
当我们新加入的值可以直接加入时,不用考虑跟最大值相邻,那么我们自然是希望跟点数更大的结果相加,然后avoid=max(usings,avoid)
表示不考虑最大值情况,正好对应了这一个值的定义
第二种情况:
当我们新加入的值跟最大值相邻时,自然要跟不考虑最大值的点数和相加即avoid
,然后更新avoid
完整代码:
int max(int a, int b)
{
return a>b?a:b;
}
int deleteAndEarn(int* nums, int numsSize){
int count[10001];
int i;
int usings=0, avoid=0;
int prev=-1;
for(i=0; i<10001; i++)
count[i]=0;
for(i=0; i<numsSize; i++)
count[nums[i]]++;
for(i=0; i<10001; i++)
if(count[i]>0)
{
int m=max(usings, avoid);
if(i!=prev+1)
{
usings=i*count[i]+m;
avoid=m;
}
else
{
usings=i*count[i]+avoid;
avoid=m;
}
prev=i;
}
return max(usings, avoid);
}
心得体会
刚开始看这道题时,因为知道这是动态规划题,所以总是想着扩展,之前做的题如子串、子矩阵等,都是扩展,但是都是从内部往往外扩展,然而做这道题时却想不到可以从一个元素从头开始扩展,而且对动态规划理解不深,自以为动态规划没办法照看到全局,因为如果从头开始扫描的话,总是牵一发而动全身,这一个决定会不会影响到后边的结果,搞得头很疼T_T、还是得多做题啊
解法思路来源于Leetcode
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/delete-and-earn
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。