「动态规划」如何计算能获得多少点数?

2024-06-10 12:44

本文主要是介绍「动态规划」如何计算能获得多少点数?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

740. 删除并获得点数icon-default.png?t=N7T8https://leetcode.cn/problems/delete-and-earn/description/

给你一个整数数组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 * 10^4,1 <= nums[i] <= 10^4。


我们用类似计数排序的思想。定义一个数组arr,arr[i]表示:在nums中,所有点数i的和。如,如果nums = [2,2,3,3,3,4],那么nums = [0,0,4,9,4],意思是:0出现0次,和为0;1出现0次,和为0;2出现2次,和为4;3出现3次,和为9;4出现1次,和为4。

那么,问题就转化为:在nums中选择一些元素,让这些元素的和最大。你不能选择相邻的元素。咦,咋这么眼熟?这不就是打家劫舍嘛!看来小偷又改行来玩游戏了,嘿嘿。我们用动态规划的思想来解决这个问题。

确定状态表示:根据经验和题目要求,我们用dp[i]表示:选到i位置的元素后,此时的最大和。再细分为:

  • 用f[i]表示:必须选择i位置的元素后,此时的最大和
  • 用g[i]表示:不能选择i位置的元素后,此时的最大和

推导状态转移方程:分别讨论2种情况中,最近的一步,即是否选择i - 1位置的元素。

  • 考虑f[i]。如果选择i位置的元素,那么就不能选择i - 1位置的元素。选择完i位置的元素之后的最大和,就等于不能选择i - 1位置的元素之后的最大和加上i位置的元素,即f[i] = g[i - 1] + arr[i]。
  • 考虑g[i]。如果不能选择i位置的元素,那么此时的最大和就等于考虑完i - 1元素之后的最大和。由于不确定是否选择i - 1位置的元素,所以不能选择i位置的元素后的最大和,就等于是否选择i - 1位置的元素这2种情况的最大和的较大值,即g[i] = max(f[i - 1], g[i - 1])。

综上所述:f[i] = g[i - 1] + arr[i],g[i] = max(f[i - 1], g[i - 1])

初始化:根据状态转移方程,在计算f[0]和g[0]时会越界,所以要对其初始化。

  • f[0]表示:必须选择0位置的元素之后,此时的最大和,显然f[0] = arr[0]。
  • g[0]表示:不能选择0位置的元素之后,此时的最大和,显然g[0] = 0。

综上所述:f[0] = arr[0],g[0] = 0

填表顺序:根据状态转移方程,f[i]依赖于g[i - 1],g[i]依赖于f[i - 1]和g[i - 1],所以应从左往右同时填f表和g表

返回值:假设arr数组有n个元素。最终要返回考虑完n - 1位置的元素后,此时的最大和。由于并不确定是否选择n - 1位置的元素,再根据状态表示,我们应返回的是,是否选择n - 1位置的元素这2种情况中,最大和的较大值,即max(f[n - 1], g[n - 1])

细节问题:由于f表和g表的下标范围是[0, n - 1],所以规模都是1 x n

时间复杂度:O(N),空间复杂度:O(N)。

class Solution {
public:int deleteAndEarn(vector<int>& nums) {const int N = 10001;// 转化问题vector<int> arr(N);for (auto num : nums) {arr[num] += num;}// 创建dp表vector<int> f(N);auto g = f;// 初始化f[0] = arr[0];// 填表for (int i = 1; i < N; i++) {f[i] = g[i - 1] + arr[i];g[i] = max(f[i - 1], g[i - 1]);}// 返回结果return max(f[N - 1], g[N - 1]);}
};

这篇关于「动态规划」如何计算能获得多少点数?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1048199

相关文章

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

Python实现精确小数计算的完全指南

《Python实现精确小数计算的完全指南》在金融计算、科学实验和工程领域,浮点数精度问题一直是开发者面临的重大挑战,本文将深入解析Python精确小数计算技术体系,感兴趣的小伙伴可以了解一下... 目录引言:小数精度问题的核心挑战一、浮点数精度问题分析1.1 浮点数精度陷阱1.2 浮点数误差来源二、基础解决

Python文本相似度计算的方法大全

《Python文本相似度计算的方法大全》文本相似度是指两个文本在内容、结构或语义上的相近程度,通常用0到1之间的数值表示,0表示完全不同,1表示完全相同,本文将深入解析多种文本相似度计算方法,帮助您选... 目录前言什么是文本相似度?1. Levenshtein 距离(编辑距离)核心公式实现示例2. Jac

Python中经纬度距离计算的实现方式

《Python中经纬度距离计算的实现方式》文章介绍Python中计算经纬度距离的方法及中国加密坐标系转换工具,主要方法包括geopy(Vincenty/Karney)、Haversine、pyproj... 目录一、基本方法1. 使用geopy库(推荐)2. 手动实现 Haversine 公式3. 使用py

浅谈MySQL的容量规划

《浅谈MySQL的容量规划》进行MySQL的容量规划是确保数据库能够在当前和未来的负载下顺利运行的重要步骤,容量规划包括评估当前资源使用情况、预测未来增长、调整配置和硬件资源等,感兴趣的可以了解一下... 目录一、评估当前资源使用情况1.1 磁盘空间使用1.2 内存使用1.3 CPU使用1.4 网络带宽二、

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

springboot如何通过http动态操作xxl-job任务

《springboot如何通过http动态操作xxl-job任务》:本文主要介绍springboot如何通过http动态操作xxl-job任务的问题,具有很好的参考价值,希望对大家有所帮助,如有错... 目录springboot通过http动态操作xxl-job任务一、maven依赖二、配置文件三、xxl-

Python并行处理实战之如何使用ProcessPoolExecutor加速计算

《Python并行处理实战之如何使用ProcessPoolExecutor加速计算》Python提供了多种并行处理的方式,其中concurrent.futures模块的ProcessPoolExecu... 目录简介完整代码示例代码解释1. 导入必要的模块2. 定义处理函数3. 主函数4. 生成数字列表5.

Java调用C#动态库的三种方法详解

《Java调用C#动态库的三种方法详解》在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们... 目录方法1:C++/CLI搭建桥梁——Java ↔ C# 的“翻译官”步骤1:创建C#类库(.NET