删除与获得点数--动态规划

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时,如果inums数组中最大的数相等或者大一位以上,那点数就是前面的点数加上i,如果inums数组中最大的数大一位,就是相邻的情况,那么我们需要引入两个值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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

猜你喜欢

转载自blog.csdn.net/jump_into_zehe/article/details/106529482
今日推荐