首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【LeetCode】动态规划—删除并获得点数(附完整Python/C++代码)

【LeetCode】动态规划—删除并获得点数(附完整Python/C++代码)

作者头像
用户9613193
发布2026-06-16 20:06:47
发布2026-06-16 20:06:47
520
举报
动态规划—#740. 删除并获得点数

  • 前言
  • 题目描述
  • 基本思路
    • 1. 问题定义:
    • 2. 理解问题和递推关系:
    • 3. 解决方法:
    • 4. 进一步优化:
    • 5. 小总结:
  • 代码实现
    • Python3代码实现
    • Python 代码解释
    • C++代码实现
    • C++ 代码解释
  • 总结:

前言

给你一个整数数组

nums

,你可以对它进行一些操作。

每次操作中,选择任意一个 n u m s [ i ] nums[i] nums[i] ,删除它并获得 n u m s [ i ] nums[i] nums[i] 的点数。之后,你必须删除 所有 等于 n u m s [ i ] − 1 nums[i] - 1 nums[i]−1 和 nums[i] + 1 的元素。

开始你拥有

0

个点数。返回你能通过这些操作获得的最大点数。

题目描述

在这里插入图片描述
在这里插入图片描述

基本思路

1. 问题定义:

在这个问题中,我们有一个数组

nums[]

,每个元素代表一个数字。你可以选择删除某个数字

x

,并获得

x

点数。然而,每当你删除一个数字

x

,与

x

相邻的数字

x-1

x+1

也会从数组中删除。问题要求的是:你通过删除数字获得的最大点数是多少?

2. 理解问题和递推关系:

这个问题类似于"打家劫舍"问题,可以转化为一个动态规划问题。每次删除某个数字时,你既获得了它的值,也会让相邻的数字无法再被选择。因此,可以把问题转化为:每个数

x

要么选择,要么跳过。

我们将问题理解为两个选择:

  1. 选择删除某个数字
x

:那么你会获得

x

出现的总值

x

*出现次数,同时不能再选择

x-1

x+1

  1. 不选择删除某个数字
x

:那么你可以选择去考虑删除其他数字。

为了将问题转化成打家劫舍的形式:

  1. 我们可以对
nums[]

进行预处理,统计每个数

x

的出现次数,然后构建一个数组

earn[]

,其中

earn [x]=x *

出现次数。

  1. 现在,问题转化为:给定一个数组
earn[]

,从中选择不相邻的数,使得获得的总和最大。这就是"打家劫舍"问题的典型形式。

3. 解决方法:

  1. 预处理:首先统计
nums[]

中每个数字的出现次数,并构建

earn[]

,即

earn[ x ]=\mathrm{x} *

出现次数。

  1. 递推公式:我们使用动态规划来解决该问题,设
d p[i]

表示前

i

个数字的最大点数。那么:

d p[i]=\max (d p[i-1], d p[i-2]+\operatorname{earn}[i])

解释:

dp[i-1]

表示我们不删除数字

i

,因此直接继承前面的最大值。

dp[i-2] + earn[i]

表示我们删除了数字

i

,因此需要加上

earn[i]

,同时要跳过

i-1

  1. 边界条件:
  • 如果数组为空,直接返回
0

  • 如果数组只有一个元素,那么返回该元素对应的
earn

值。

4. 进一步优化:

在上述方法中,我们使用了一个数组

d p[]

来保存每个位置的最大点数。但实际上,

d p[i]

只依赖于

d p[i-1]

和 dp[i-2],因此可以通过使用两个变量来优化空间复杂度,从

O(n)

降低到

O(1)

  • 时间复杂度:
O(n)

,因为我们需要遍历数组构建

earn[]

,以及进行动态规划。

  • 空间复杂度:通过优化后可以降低到
O(1)

,只需要常量空间保存前两个状态。

5. 小总结:

  • 问题核心:通过删除某个数获得它的总值,并且不能删除与它相邻的数。这个问题转化为典型的动态规划问题。
  • 动态规划:通过计算每个数出现的总值
earn[x]

,将问题简化为选择不相邻的数求最大和的问题。

  • 优化:使用两个变量保存前两个状态,减少空间消耗。

以上就是删除并获得点数问题的基本思路。

代码实现

Python3代码实现

代码语言:javascript
复制
class Solution:
    def deleteAndEarn(self, nums: list[int]) -> int:
        if not nums:
            return 0
        
        # 统计每个数字的总收益
        max_num = max(nums)
        earn = [0] * (max_num + 1)
        for num in nums:
            earn[num] += num
        
        # 使用动态规划来解决打家劫舍问题
        prev2, prev1 = 0, 0
        
        for i in range(len(earn)):
            current = max(prev1, prev2 + earn[i])
            prev2 = prev1
            prev1 = current
        
        return prev1

Python 代码解释

  1. 边界条件:如果
nums[]

为空,直接返回

0

  1. 统计:我们遍历
nums[]

,构建

earn[]

,其中

earn[x] = x *

出现次数。

  1. 动态规划:通过
prev2

prev1

来存储前两个状态的最大值,然后根据递推公式依次更新,最终返回

prev1

即为最大值。

C++代码实现

代码语言:javascript
复制
class Solution:
    def deleteAndEarn(self, nums: list[int]) -> int:
        if not nums:
            return 0
        
        # 统计每个数字的总收益
        max_num = max(nums)
        earn = [0] * (max_num + 1)
        for num in nums:
            earn[num] += num
        
        # 使用动态规划来解决打家劫舍问题
        prev2, prev1 = 0, 0
        
        for i in range(len(earn)):
            current = max(prev1, prev2 + earn[i])
            prev2 = prev1
            prev1 = current
        
        return prev1

C++ 代码解释

  1. 边界条件:如果
nums[]

为空,直接返回

0

  1. 统计:构建
earn[]

数组,存储每个数字的总收益。

  1. 动态规划:使用两个变量
prev2

prev1

来分别存储前两个状态的最大收益,遍历数组

earn[]

,最终返回

prev1


总结:

  • 动态规划是解决此类问题的核心,将删除数字及其邻居的问题转化为典型的选择不相邻数的问题。
  • 优化空间:通过使用常量空间,减少了数组存储的开销,使得算法在时间和空间上都更高效。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-06-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 动态规划—#740. 删除并获得点数
  • 前言
  • 题目描述
  • 基本思路
    • 1. 问题定义:
    • 2. 理解问题和递推关系:
    • 3. 解决方法:
    • 4. 进一步优化:
    • 5. 小总结:
  • 代码实现
    • Python3代码实现
    • Python 代码解释
    • C++代码实现
    • C++ 代码解释
  • 总结:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档