LeetCode 删除与获得点数(动态规划+hash表)

版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/qq_41855420,未经博主允许不得转载。 https://blog.csdn.net/qq_41855420/article/details/89761977

给定一个整数数组 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的长度最大为20000。
每个整数nums[i]的大小都在[1, 10000]范围内。

思路分析: 首先我们対删除操作进行简化,我们把每次删除一个数扩大为每次删除一种数nums[index],并且剔除nums[index] - 1,nums[index] + 2这两种数。比如示例2,输入: nums = [2, 2, 3, 3, 3, 4],我们先删除3(一共有三个,所以可以获得9),然后剔除3 - 1(一共有两个),3 + 1(一共有一个)。不难理解,这和一个一个的删除3是一样的结果。因此我们先需要将所有数按照值的大小进行分类,使用hash表将{值,个数}关联即可。接下来就有点像 LeetCode 打家劫舍(动态规划) ,num - 1,num,num + 1可以看做地理上的相邻,如果删除num,就不能删除num - 1,num + 1。

第一步:使用hashMap统计各个元素出现的次数,然后按照first排序
第二步:将hashMap转换为数组,如果a == b + 1或者a - 1 == b,则将a、b相邻。
第三步:使用动态规划算法进行求解最大值。
class Solution {
public:
    int deleteAndEarn(vector<int>& nums) {
        if (nums.empty()){
            return 0;
        }
        //第一步:使用hashMap统计各个元素出现的次数,然后按照first排序
        map<int, int, less<int>> hashMap;//{first, second},first代表num,second代表num的个数
        for (auto num : nums){
            hashMap[num] += 1;
        }
        //第二步:将hashMap转换为数组,如果a == b + 1或者a - 1 == b,则将a、b相邻。
        int hashMapSize = (int)hashMap.size();
        vector<pair<int, int>> myNums;//{first, second},first代表num,second代表删除num可获得的大小
        for (auto &item : hashMap){
            if (!myNums.empty() && myNums.back().first + 1 != item.first){
                //如果当前元素不与上一个元素(myNums的最后一个元素)响铃,则中间需要间隔一个空元素
                myNums.push_back({item.first + 1, 0});
            }
            myNums.push_back({item.first, item.first * item.second});
        }
        //第三步:使用动态规划算法进行求解最大值。
        int myNumsSize = (int)myNums.size();
        vector<int> dp(myNumsSize, 0);//dp[index]表示在myNums第index个位置可获得最大值
        dp[0] = myNums[0].second;//対dp[0],dp[1]进行初始化
        if (myNumsSize > 1){
            dp[1] = max(myNums[1].second, dp[0]);
        }
        for (int index = 2; index < myNumsSize; ++index){
            //转移方程:dp[index - 2] + myNums[index].second代表的是偷myNums[index](意味着可以偷dp[index - 2]),可获得的值
            //dp[index - 1]代表不偷取myNums[index],则只能获得dp[index - 1]
            dp[index] = max(dp[index - 2] + myNums[index].second, dp[index - 1]);
        }
        return dp[myNumsSize - 1];
    }
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/89761977
今日推荐