LeetCode题解 动态规划(四):416 分割等和子集;1049 最后一块石头的重量 II

news2024/12/23 16:18:17

背包问题

下图将背包问题做了分类

416.分割等和子集1

其中之重点,是01背包,即一堆物件选哪样不选哪样放入背包里。难度在于,以前的状态转移,多只用考虑一个变量,比如爬楼梯的阶层,路径点的选择,这也是能用滚动数组表示动态规划的原因,而现在要同时考虑两个:物品和背包容量。

01背包

有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

使用动态规划五部曲:

1 - 确定dp数组含义:有一种写法, 是使用二维数组,即dp[i] [j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少

2 - 到了第 i 件物品的时候,背包容量为 j ,但就放不放物品,两种选择:

  • 不放第 i 件物品,那么背包容量不变,从dp[i - 1] [j]状态而来
  • 放第 i 件物品,那么就会从dp[i - 1] [j - weight[i]]状态而来,因为至少得有足够的空间将物品放进去才行。

所以递归公式: dp[i] [j] = max(dp[i - 1] [j], dp[i - 1] [j - weight[i]] + value[i]);

3 - 初始化dp数组:如果是01背包的话,背包容量如果为零,那么价值也一定为零。而能放入第一件物品的时候,就是其对应的价值。

动态规划-背包问题3

4 - 遍历顺序:这一步比较重要,在初期理解01背包的时候会显得有一点难以理解。但总归记住,就是一个二维数组,和之前的题目一样,先遍历物品再遍历背包容量(物品固定,尝试一点点把物品塞进去),和先遍历背包容量再遍历物品(背包容量固定,尝试能塞进去哪个)都是可以的。

从数组的角度考虑这一点也是可以的,根据递推公式,当前状态是从数组的左上角位置而来,只要保持是这个方向就可以了。就和我们之前求解路径问题时一样。

5 - 举例推导

假设背包最大重量为4。

物品为:

重量价值
物品0115
物品1320
物品2430

那么数组的最终状态就如下图所示:

动态规划-背包问题4

关于01背包,也有使用一维数组,即滚动数组的方法。其核心思想是,如果不放物品,dp[j]其实就是自己本身,如果要放物品,那么dp[j] 就是考虑从一个能放下这个物品的背包,塞入该物品,即dp[j - weight[i]] + value[i]。

遍历顺序就是不能是从一个空背包开始放了,而是从一个满的背包里尝试取出某件物品,这样做是为了保证物品只被放入一次。这么做也是有现实依据的,就是先考虑所有能用得上的东西,再从这些物品里挑出来不是那么重要的物品。

我私认为,注重理论推导,就可以在后期的解题过程中方便不少,但是也不必过于纠结能否“记住理论”,还是要投入实际应用才能更好的理解理论。

接下来,进入解题过程。

416 分割等和子集 medium

给你一个 只包含正整数非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

为什么说动态规划难呢?我认为是不少时候压根意识不到该用动态规划求解问题。

关于这道题,首先要想到要对整个数组求和,如果和是奇数,咋分都分不出来。

如果是偶数,那么所有数之和的一半,就是我们期望的“背包最大容量”,剩下的事情就是把数字填进去就可以了,和01背包完全一样。

根据这个思想,代码如下:

bool canPartition(vector<int>& nums) {
    int sum = 0;
    for (int num: nums)
        sum += num;
    if (sum % 2 == 1) return false;
    int target = sum / 2;

    vector<int> dp(10001, 0); // 题目中给出数组长度最大是200,值最大是100,取总和的一半肯定够了
    // 我们采用先遍历数字的方式
    for (int i = 0; i < nums.size(); ++i) {
        for (int j = target; j >= nums[i]; --j) {
            dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
        }
    }

    return dp[target] == target;
}

1049 最后一块石头的重量 II medium

有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。

每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。

实不相瞒,以我现在的水平,看到这道题,我还是想不到应该用动态规划来做,但是多少有点儿那个味儿了。

要使最后剩下的石块重量尽可能小,就需要能撞掉的石头尽可能多,所以这道题可以看成是背包容量为[总重量/2](向下取整),物品价值就是石头重量的0-1背包问题。

求解方式和上面的题几乎一模一样,代码如下:

int lastStoneWeightII(vector<int>& stones) {
    int totalWeight = 0;
    for (int stoneWeight: stones)
        totalWeight += stoneWeight;

    vector<int> dp(15001, 0);
    int target = totalWeight / 2;

    for (int i = 0; i < stones.size(); ++i) {
        for (int stonesWeight = target; stonesWeight >= stones[i]; --stonesWeight) {
            dp[stonesWeight] = max(dp[stonesWeight], dp[stonesWeight - stones[i]] + stones[i]);
        }
    }
    return totalWeight - 2 * dp[target];
}

说到这里,可能还是有人不太明白为什么能这么写,之所以要尽量的往总数量一半的背包里塞,就说明这些都是希望能尽量被撞掉的,可以证明,如果能达到一半的容量,那么其必然可以全部被撞掉,所以最后要减去2倍的dp[target]。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/337414.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT 的未来挑战和风险

ChatGPT 是 OpenAI 开发的流行语言模型&#xff0c;彻底改变了我们与 AI 交互的方式。然而&#xff0c;随着像 ChatGPT 这样的语言模型的使用越来越广泛&#xff0c;重要的是要考虑它们未来可能面临的潜在风险和挑战。 一、数据质量和公平性 使用 ChatGPT 的主要风险之一是用于…

大数据-------元数据管理

一、什么是元数据 元数据就是描述数据的数据&#xff0c;它为企业的各类数据提供了上下文环境&#xff0c;使企业能够更好地了解、管理和使用数据。 现在数据对于公司的决策十分的重要&#xff0c;随着业务的发展&#xff0c;业务线会慢慢庞大起来&#xff0c;随着开发人员的…

九、STM32定时器讲解 - 通用定时器实战

目录 1.三种定时器的区别 2.通用定时器的特点描述 3.计数器模式 4.通用定时器工作过程 5.计数器时钟计算方法、 5.1定时器的输入时钟频率 - TimeClockFren 5.2计数器时钟计算方法 6.定时器相关寄存器 7.定时器库函数结构体 8.通用定时器函数 9.定时器中断配置过程 1…

图论算法:树上倍增法解决LCA问题

文章目录树上倍增法&#xff1a; LCA问题树上倍增法&#xff1a; LCA问题 树上倍增法用于求解LCA问题是一种非常有效的方法。 倍增是什么&#xff1f; 简单来说&#xff0c;倍增就是 1 2 4 8 16 … 2^k 可以发现倍增是呈 2的指数型递增的一类数据&#xff0c;和二分一样&…

黑马程序员 Linux 教程

目录Linux 简介不同应用领域主流操作系统Linux 系统历史Linux 系统版本Linux 安装安装方式网卡设置安装 SSH 连接工具使用 FinalShell 连接到 LinuxLinux 和 Windows 目录结构对比Linux 目录介绍Linux 常用命令Linux 命令初体验Linux 命令使用技巧Linux 命令格式文件目录操作命…

Python的文件编码,复制,缓冲,删除

能力有限&#xff0c;仅供参考 本篇博文是上一篇博文&#xff08; Python的文件读取&#xff0c;写入&#xff09;的后续&#xff0c;也是python文件管理的一部分&#xff0c;废话不多说&#xff0c;现在就开始。 1. 编码 在实际工作学习中&#xff0c;你可以遇到乱码的问题…

c语言递归 累和 ,累乘积,斐波那契数列,字符串长度

目录 递归使用场景 1:使用递归的方式计算 Sn123..100 2&#xff1a;计算 n&#xff01;n*(n-1)*(n-2)*......*1; 3:计算输出斐波那契数列前20项&#xff0c;并按每行4个数的格式输出(2019年&#xff09; 4&#xff1a; 用递归和非递归两种方式编写函数strlength()。该函数…

Nacos 入门微服务项目实战

Nacos 核心源码精讲 - IT贱男 - 掘金小册全方位源码精讲&#xff0c;深度剖析 Nacos 注册中心和配置中心的核心思想。「Nacos 核心源码精讲」由IT贱男撰写&#xff0c;375人购买https://s.juejin.cn/ds/BuC3Vs9/ Hi&#xff0c;大家好&#xff0c;欢迎大家来学习《Nacos 核心源…

2022黑马Redis跟学笔记.基础篇(一)

2022黑马Redis跟学笔记.基础篇 一1.Redis入门1.1.认识NoSQL1.1.1.结构化与非结构化1.1.2.关联和非关联1.1.3.查询方式1.1.4.事务1.1.5.总结1.2.认识Redis1.3.安装Redis步骤一&#xff1a;安装Redis依赖步骤二&#xff1a;上传安装包并解压步骤三&#xff1a;启动(1).默认启动(2…

开发微服务电商项目演示(三)

一&#xff0c;nginx动静分离第1步&#xff1a;通过SwitchHosts新增二级域名&#xff1a;images.zmall.com第2步&#xff1a;将本次项目的易买网所有静态资源js/css/images复制到nginx中的html目录下第3步&#xff1a;在nginx的核心配置文件nginx.conf中新增二级域名images.zma…

论文阅读:MINE: Towards Continuous Depth MPI with NeRF for Novel View Synthes

中文标题&#xff1a;基于连续深度多平面和神经辐射场的新视角合成 本文只介绍与NeRF原文不同的部分 创新点 对单一图像进行密集三维重建&#xff0c;完成新视角合成与深度估计的工作。从单个图像生成连续和遮挡绘制的三维重建。MINE借鉴NeRF可以生成连续的深度图像。 解决…

leaflet上传CSV文件,在地图上显示图形(示例代码054)

第054个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中加载CSV文件,将图形显示在地图上。CSV(逗号分隔值)文件是一种简单且开放的文件格式,以纯文本形式存储表格数据。 几乎所有电子表格和数据库软件都可以导入/导出这种文件格式。 直接复制下面的 vue+ope…

Navicat无法连接MySQL报错1251的解决方法

日期&#xff1a;2023年2月10日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

C++中的智能指针

1.RAII 与引用计数了解 Objective-C/Swift 的程序员应该知道引用计数的概念。引用计数这种计数是为了防止内存泄露而产生的。 基本想法是对于动态分配的对象&#xff0c;进行引用计数&#xff0c;每当增加一次对同一个对象的引用&#xff0c;那么引用对象的引用计数就会增加一次…

[AAAI 2022] TransFG: A Transformer Architecture for Fine-grained Recognition

Contents TransFG ArchitectureExperimentsReferencesTransFG Architecture Overlapping patch split:ViT 是把图片分成一系列不重叠的 patches,作者认为这可能会破坏 discriminative regions. 为了解决上述问题,作者提出使用 Overlapping patch split,划分的 patch 数 N …

消息中间件RabbitMQ

文章目录1. 协议2. RabbitMQ架构原理3.内存管理4.磁盘控制5. RabbiMQ 插件管理6. 死信6.1 死信队列6.2 延时插件7. 高可用集群方案7.1 普通集群模式7.2 镜像集群模式7.3 基于HAproxyKeepalived搭建高可用8.可靠性投递8.1 消息从生产者发送到Broker两种确认机制8.2 消息从Exchan…

数据Kylin(三):Kylin配置

Kylin配置 一、kylin.metadata.url 指定元数据库路径,默认值为 kylin_metadata@hbase 二、kylin.metadata.sync-retries 指定元数据同步重试次数,默认值为 3 三、kylin.env.hdfs-working-dir 指定 Kylin 服务所用的 HDFS 路径,默认值为 /kylin,请确保启动 Kylin 实例的用户…

【面试题】对闭包的理解?什么是闭包?

大厂面试题分享 面试题库后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★地址&#xff1a;前端面试题库闭包的背景由于js中只有两种作用域&#xff0c;全局作用域和函数作用域&#xff0c;而在开发场景下&#xff0c;将变量暴露在全局作用域下的时候…

云盘满了怎么办?阿里云服务器云盘扩容操作了解一下

1.背景 2.确定扩容云盘类型与控制台操作 3.ECS实例内部扩容操作说明 3.1 ECS实例内部执行扩容分区 3.2 ECS实例内部执行扩容文件系统 1.背景软件应用的数据库所在服务器磁盘使用率已经达到97%,服务器操作实例如下: 一旦使用达到上限,所有的数…

python基于django的 大学生健康管理系统

随着时代的发展,大学生的数量与日预增但是相对的也出现了很多心理问题,大学生因为各类心理引发的社会问题已经受到了很多人的关注,所以如何更好的培养大学生正确的心理健康问题是现在很多大学多面临的一个重要的问题。 系统设置了三种身份的登录,包括管理员,医生和学生。其中管…