当前位置: 首页 > news >正文

【算法】动态规划 斐波那契类型: 740. 删除并获得点数

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 个点数。

提示:

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


分析

这是一个非常经典的动态规划问题,跟「打家劫舍」非常相似

问题本质:

  • 如果你选了一个数 x,你会获得 x * 出现次数 的分数,并且不能再选 x-1x+1
  • 所以你不能同时选相邻的数(按照值排序)。
  • 相当于:把所有数按照值排序,把它们看成一排房子(每个房子有一定价值),不能取相邻的房子。

下面一步一步讲解和给出代码。


🟢 思路步骤

  1. 统计每个数字的总价值:

    • 用一个数组 sum[x] = x * 出现次数

    • 例如 nums = [2,2,3,3,3,4]

      • 2出现2次,贡献=2*2=4
      • 3出现3次,贡献=3*3=9
      • 4出现1次,贡献=4*1=4
  2. 动态规划:

    • 定义 dp[i]:考虑数字0~i,能取得的最大分数。

    • 转移方程:

      dp[i] = max(dp[i-1],            // 不取idp[i-2] + sum[i]    // 取i
      )
      
    • 为什么和打家劫舍一样?因为选了i就不能选i-1。

  3. 初始化:

    • dp[0] = sum[0]
    • dp[1] = max(sum[0], sum[1])
  4. 返回:

    • dp[max_value]max_value = max(nums)

🟢 Python代码

def deleteAndEarn(nums):if not nums:return 0max_num = max(nums)sum_points = [0] * (max_num + 1)# 统计每个数的总价值for num in nums:sum_points[num] += num# 动态规划dp = [0] * (max_num + 1)dp[0] = sum_points[0]dp[1] = max(sum_points[0], sum_points[1])for i in range(2, max_num + 1):dp[i] = max(dp[i - 1], dp[i - 2] + sum_points[i])return dp[max_num]

🟢 示例验证

示例1:

nums = [3,4,2]
sum_points: [0,0,2,3,4]
dp:
i=2: dp[2]=max(dp[1], dp[0]+sum[2]) = max(0,0+2)=2
i=3: dp[3]=max(dp[2], dp[1]+sum[3]) = max(2,0+3)=3
i=4: dp[4]=max(dp[3], dp[2]+sum[4]) = max(3,2+4)=6
输出:6

示例2:

nums = [2,2,3,3,3,4]
sum_points: [0,0,4,9,4]
dp:
i=2: dp[2]=max(dp[1], dp[0]+sum[2]) = max(0,0+4)=4
i=3: dp[3]=max(dp[2], dp[1]+sum[3]) = max(4,0+9)=9
i=4: dp[4]=max(dp[3], dp[2]+sum[4]) = max(9,4+4)=9
输出:9

✅完全符合题意。


c++


🟢 C++代码

#include <vector>
#include <algorithm>
using namespace std;class Solution {
public:int deleteAndEarn(vector<int>& nums) {if (nums.empty()) return 0;int maxNum = *max_element(nums.begin(), nums.end());// sum[i] = i * 出现次数vector<int> sum(maxNum + 1, 0);for (int num : nums) {sum[num] += num;}// dp[i] = 考虑[0..i]的最大点数vector<int> dp(maxNum + 1, 0);dp[0] = sum[0];dp[1] = max(sum[0], sum[1]);for (int i = 2; i <= maxNum; ++i) {dp[i] = max(dp[i - 1], dp[i - 2] + sum[i]);}return dp[maxNum];}
};

🟢 用法示例

你可以这样调用:

#include <iostream>int main() {Solution s;vector<int> nums = {2,2,3,3,3,4};cout << s.deleteAndEarn(nums) << endl;  // 输出 9return 0;
}

**空间优化(O(1)空间)**


非常好问题!

这个DP转移:

d p [ i ] = max ⁡ ( d p [ i − 1 ] , d p [ i − 2 ] + s u m [ i ] ) dp[i] = \max(dp[i-1], dp[i-2] + sum[i]) dp[i]=max(dp[i1],dp[i2]+sum[i])

只用到了 i-1i-2,所以不需要存整个数组,只需要两个变量即可。


🟢 O(1)空间优化思路

  • 维护两个变量:

    • prev1:表示 dp[i-1]
    • prev2:表示 dp[i-2]
  • 每次更新:

    curr = max(prev1, prev2 + sum[i]);
    

    然后:

    prev2 = prev1;
    prev1 = curr;
    

🟢 完整C++代码(O(1)空间)

#include <vector>
#include <algorithm>
using namespace std;class Solution {
public:int deleteAndEarn(vector<int>& nums) {if (nums.empty()) return 0;int maxNum = *max_element(nums.begin(), nums.end());vector<int> sum(maxNum + 1, 0);for (int num : nums) {sum[num] += num;}int prev2 = sum[0];                        // dp[i-2]int prev1 = max(sum[0], sum[1]);           // dp[i-1]int curr = prev1;for (int i = 2; i <= maxNum; ++i) {curr = max(prev1, prev2 + sum[i]);prev2 = prev1;prev1 = curr;}return curr;}
};

🟢 样例验证

如示例:

int main() {Solution s;vector<int> nums = {2,2,3,3,3,4};cout << s.deleteAndEarn(nums) << endl;  // 输出 9return 0;
}

✅ 输出正确。

这样就只用 O(1) 空间,时间复杂度依然是 O(N)。

如需要,我也可以帮你写 Java版本 或进一步优化逻辑!
在这里插入图片描述

http://www.lryc.cn/news/578366.html

相关文章:

  • 设计模式之上下文对象设计模式
  • IntelliJ IDEA 2025- 下载安装教程图文版详细教程(附激活码)
  • 使用nlohmann/json.hpp实现json文件读写
  • SpringBoot全局异常详解
  • 【实时Linux实战系列】实时数据库与数据存储方案
  • 学习threejs,使用自定义GLSL 着色器,生成艺术作品
  • 使用Rust原生实现小波卡尔曼滤波算法
  • 408第三季part1 - 操作系统 - 基本分页
  • 算法赋能管理:工厂安全与效率双突破
  • 【仿muduo库实现并发服务器】Channel模块
  • 回转体航行器控制系统中深度控制与俯仰姿态控制的解耦策略
  • 基于springboot的养老院管理系统
  • C# Linq to XML 详解:强大的XML处理工具
  • (自用)Java学习-5.21(支付宝沙箱支付、Vue总结)
  • 插入排序解析
  • sqlmap学习笔记ing(1.Easy_SQLi(时间,表单注入))
  • Django打造智能Web机器人控制平台
  • HarmonyOS应用开发高级认证知识点梳理 (一) 布局与样式
  • 记本好书:矩阵力量:线性代数全彩图解+微课+Python编程
  • 深蓝海域承建某大型保险集团产险知识库升级项目
  • 主流零信任安全产品深度介绍
  • 11OAuth2
  • 从零到一搭建远程图像生成系统:Stable Diffusion 3.5+内网穿透技术深度实战
  • 【深度学习1】ModernBert学习
  • 发布/订阅模式:解耦系统的强大设计模式
  • Spring Boot 集成 Dufs 通过 WebDAV 实现文件管理
  • 从零到一:VNC+内网穿透技术搭建企业级远程控制系统的完整路径
  • ubuntu系统安装docker 和 mongdb,YaPi(包含中间过程不能拉去依赖问题)
  • langchain从入门到精通(三十二)——RAG优化策略(八)自查询检索器实现动态数据过滤
  • 自由学习记录(66)