动态规划-简单多状态dp问题 -- 删除并获得点数

动态规划-简单多状态dp问题 – 删除并获得点数

题目重现

题目链接:删除并获得点数 - 力扣

给你一个整数数组 nums ,你可以对它进行一些操作。

每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除 所有 等于 nums[i] - 1nums[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 个点数。

提示:

  • 1 <= nums.length <= 2 * 104
  • 1 <= nums[i] <= 104

读懂题目

根据题目描述,选择 x 数字的时候, x - 1 与 x + 1 是不能被选择的。像「打家劫舍」问题中,选择 i 位置的金额之后,就不能选择 i - 1 位置以及 i + 1 位置的金额。因此,我们可以创建一个大小为 10001 (根据题目的数据范围)的 hash 数组,将 nums 数组中每一个元素 x ,累加到 hash 数组下标为 x 的位置处,然后在 hash 数组上来一次「打家劫舍」即可。

算法流程

1.状态表示

用 dp[i] 表示以 i 位置为结尾对应的最大点数,但是考虑到对于每个 i 位置都存在两种情况:选择与不被选择。所以我们将 dp[i] 拆分为两种状态表示,不妨表示为 f[i]、g[i] ,其含义分别为:

f[i]:选择 i 位置,以 i 位置为结尾对应的最大点数

g[i]:选择 i 位置,以 i 位置为结尾对应的最大点数

2.状态转移方程

hash 表我们将其数组名定义为:num_countadd_set,根据 “读懂题目” 部分的内容,我们需要明确 num_countadd_set 数组的下标对应的是题中所给 nums 数组元素值。

比如:数字2580在 nums 数组中出现了 4 次,那么 num_count_set 就应该在下标为 2580 处的值为 2580*4 = 10320 。

这样设计的初衷是为了对应题目要求:选择一个 nums[i] ,删除它并获得 nums[i] 的点数并删除 所有 等于 nums[i] - 1nums[i] + 1 的元素。如此设计就可以避免选择了点数为 nums[i] 的位置后还会选择到点数为 nums[i] + 1 或 nums[i] - 1 的位置。

于此,根据常规的打家劫舍问题,就能得到状态转移方程:

  • f[i] = g[i - 1] + num_countadd_set[i]
  • g[i] = max(f[i - 1], g[i - 1])

3.初始化

由于填表时总是需要前一个位置的值,所以需要初始化 f[0] 和 g[0] 的值:

  • f[0] = num_countadd_set[0];
  • g[0] = 0;

4.填表顺序

从左往右,两表同填

5.返回值

dp表最后一个位置对应的值就是整个数组满足题意的最大点数,所以返回值为:

max(f[N - 1], g[N - 1]);

示例代码

class Solution {
public:
    int deleteAndEarn(vector<int>& nums) {
        int n = nums.size();
        const int N = 10001;
        int num_countadd_set[N] = {0};
        for(auto e: nums)
        {
            num_countadd_set[e] += e;
        }

        vector<int> f(N);   // 选nums[i], 最大分钟数
        auto g = f;   // 不选nums[i], 最大分钟数

        f[0] = num_countadd_set[0];
        g[0] = 0;

        for(int i = 1; i < N; i++)
        {
            f[i] = g[i - 1] + num_countadd_set[i];
            g[i] = max(f[i - 1], g[i - 1]);
        }

        return max(f[N - 1], g[N - 1]);
    }
};

提交结果:

在这里插入图片描述

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

螺蛳粉只吃炸蛋的走风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值