力扣● 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

news2024/9/29 15:34:41

● 1049. 最后一块石头的重量 II

题目要把石头分成两堆,这两堆的重量差值最小。相撞之后剩下的石头重量就最小。其实就是要尽量把石头分为差不多重量的两堆,和昨天的● 416. 分割等和子集相似,这样就转换成了01背包问题。

和416题一样,背包里面放的是两堆其中一堆的石头,需要尽量装满sum/2,其中一堆越接近sum/2,两堆石头重量就越差不多。所以这里价值和重量是等同的 ,weight数组就是stones数组,value数组也是stones数组。容量begweight就得取sum/2。

代码如下,注意最后返回的是另一堆的重量减去背包里的重量,因为背包重量≤sum/2,所以另一堆重量≥背包重量。

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int sum=0;
        for(int a:stones)sum+=a;//求和
        int begweight=sum/2;//背包容量
        vector<int> dp(begweight+1,0);  //已初始化
        for(int i=0;i<stones.size();++i){
            for(int j=begweight;j>=stones[i];--j){
                dp[j]=max(dp[j],dp[j-stones[i]]+stones[i]); //weight和value数组都是stones
            }
        }
        return (sum-2*dp[begweight]);   //dp[begweight]是背包里的重量
    }
};

● 494. 目标和

在每个数前面要么添加"+",要么添加"-",所以也是分为两堆:设为left和right。添加"+"的是left,添加"-"的是right。

有:left-right=target;left+right=sum。

所以left=(sum+target)/2。其中sum和target都已知,所以left可知,问题就是在集合nums中统计和为left的组合数量。所以背包容量应该为left的值。

有两个情况可以直接返回:如果sum+target的和是奇数,那left是不存在的,返回0;如果target的绝对值比sum还大,怎么添加"+"和"-"都不会得到left,也返回0.

动归五部曲:

1. DP数组及其下标的含义。dp[j]:装满容量为j的包,有dp[j]种方法。

所以和昨天的不同,这个是装满容量为j,所以背包容量直接就是j,昨天的是最大容量为j。而且这个是组合问题。所以五部曲得重新思考。


2. 递推公式。dp[j]背包现在容量是j,考虑最后放入的物品,有可能是小于等于j的物品中的任意一个,那么对于所有的nums[i]≤j,都可能是最后一步放入的。所以放一个其中的nums[i],对应的方法数应该是dp[j-nums[i]]。所以统计dp[j]就得考虑所有的小于j的nums[i]在背包里面的情况,那么就需要把所有的dp[j-nums[i]]加起来,才是dp[j]的值。例子如下:

dp[j],j 为5。如果小于j的nums[i]有1,2,3,4,5,那么5种情况,都考虑,然后一起加上。
  • 已经有一个1(nums[i]) 的话,有 dp[4]种方法 凑成 容量为5的背包。
  • 已经有一个2(nums[i]) 的话,有 dp[3]种方法 凑成 容量为5的背包。
  • 已经有一个3(nums[i]) 的话,有 dp[2]中方法 凑成 容量为5的背包。
  • 已经有一个4(nums[i]) 的话,有 dp[1]中方法 凑成 容量为5的背包。
  • 已经有一个5 (nums[i])的话,有 dp[0]中方法 凑成 容量为5的背包。

所以dp[j]= \sum_{nums[i]\leq j}^{}dp[j-nums[i]]

这个公式在后面背包解决排列组合问题的时候还会用到。

3. DP数组如何初始化。dp[0] 需要= 1,虽然=1不好解释,但是如果初始化为0的话,之后怎么加结果都只会是0,所以肯定是不行的。

4. 遍历顺序。昨天滚动一维数组中说过的,先物品再背包,而且背包要倒序。


5. 打印DP数组。动手模拟,输出检查。

输入:nums: [1, 1, 1, 1, 1], S: 3

bagweight = (S + sum) / 2 = (3 + 5) / 2 = 4

dp数组状态变化如下:

代码:

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum=0;
        for(int a:nums)sum+=a;
        //2种没有结果的情况
        if(abs(target)>sum)return 0;
        if((sum+target)%2==1)return 0;
        //背包容量begweight=left=(sum+target)/2
        int begweight=(sum+target)/2;
        vector<int> dp(begweight+1,0);
        //不能是0.
        dp[0]=1;
        for(int i=0;i<nums.size();++i){
            for(int j=begweight;j>=nums[i];--j){
                dp[j]+=dp[j-nums[i]];
            }
        }
        return dp[begweight];
    }
};

● 474.一和零

输入有m和n,输出包含m个0和n个1的子集的最大长度。那么dp数组应该有两个维度,最后应该返回dp[m][n]。

动规五部曲:

1. DP数组及其下标的含义。

dp[i][j]:背包里面有 i 个0和 j 个1,可以最多装下dp[i][j]个物品(集合)。


2. 递推公式。

每个物品的重量/价值也应该是两个维度:x个0和y个1。所以有value0和value1两个数组,统计出每个物品两个维度的价值。这个题和前几个一样,价值 和重量一样,所以下面统称重量。

回想之前一维滚动数组的递推公式:dp[ j ]=max(dp[ j ], dp[ j - weight[ i ]] +value[ i ]);可见这个公式的重要性,所以还是根据这种思想,对于每个物品(每个k),都考虑没放进来之前的背包重量,是dp[ i- x ] [ j - y ],放不进去的话就取上一轮的dp[i][j]。所以递推公式仍然是取这两种情况的最大值:

dp[ i ][ j ]=max( dp[ i ][ j ], dp[ i- x ] [ j - y ] + 1)。

注意这个是一维滚动数组的变形,但是因为dp数组扩展成二维,所以之前一维滚动数组的循环j这y一层循环应该变成两层循环i和j,加上最外层循环应该有3层for循环。


3. DP数组如何初始化。显然dp[0][0]是0,其他的值为了不会出现递推公式里面取max取到自己随便设置的一个正数,也应该都初始为0。


4. 遍历顺序。同样是先物品再背包,且背包有二维,i和j都应该倒序遍历,而且条件要使得递推公式的下标有效。


5. 打印DP数组。

以输入:["10","0001","111001","1","0"],m = 3,n = 3为例

代码如下:

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m+1,vector<int>(n+1,0));    
        for(string str:strs){
            int x=0,y=0;
            //统计x和y
            for(char s:str){
                if(s=='0')  x++;
                else y++;
            }
            //二维递推
            for(int i=m;i>=x;--i){
                for(int j=n;j>=y;--j){
                    dp[i][j]=max(dp[i][j],dp[i-x][j-y]+1);
                }
            }
        }
        return dp[m][n];
    }
};

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

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

相关文章

【字符串相加】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 字符串相加 方法一&#xff1a; 方法二&#xff1a; 总结 前言 世上有两种耀眼的光芒&#xff0c;一种是正在升起的太阳&#xff0c;一种是正在努力学习编程的…

腾讯云幻兽帕鲁游戏存档迁移教程,本地单人房迁移/四人世界怎么迁移存档?

腾讯云幻兽帕鲁游戏存档迁移的方法主要包括以下几个步骤&#xff1a; 登录轻量云控制台&#xff1a;首先&#xff0c;需要登录到轻量云控制台&#xff0c;这是进行存档迁移的前提条件。在轻量云控制台中&#xff0c;可以找到接收存档的服务器卡片&#xff0c;并点击进入实例详情…

LeetCode 2368.受限条件下可到达节点的数目:搜索 + 哈希表

【LetMeFly】2368.受限条件下可到达节点的数目&#xff1a;搜索 哈希表 力扣题目链接&#xff1a;https://leetcode.cn/problems/reachable-nodes-with-restrictions/ 现有一棵由 n 个节点组成的无向树&#xff0c;节点编号从 0 到 n - 1 &#xff0c;共有 n - 1 条边。 给…

ecmascript 6+(2)

引用数据类型&#xff1a; Object, Array, RegExp, Date等 包装类型&#xff1a;&#xff08;底层数据类型会将简单数据类型包装为对象&#xff09; String, Number, Boolean等&#xff08;都是基本数据类型的构造函数&#xff09; Object Object.keys(对象) 返回数组&…

ctf_show笔记篇(web入门---php特性)

目录 php特性 89&#xff1a;直接数组绕过preg_match当遇到数组时会直接报错输出0 90&#xff1a;这里利用了intval的特性 91&#xff1a;这里需要细节一点 92-93&#xff1a;这两题的方法很多可以发散思维 94&#xff1a;还是利用小数绕过例如4476.0 95&#xff1a;这里…

spring boot 修复 Spring Framework URL解析不当漏洞(CVE-2024-22243)

漏洞描述 当应用程序使用UriComponentsBuilder来解析外部提供的URL&#xff08;如通过查询参数&#xff09;并对解析的URL的主机执行验证检查时可能容易受到Open重定向攻击和SSRF攻击&#xff0c;导致网络钓鱼和内部网络探测等。 受影响产品或系统 6.1.0 < Spring Framew…

【bioinformation 2】生物数据库

&#x1f31e;欢迎来到AI医学的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f4c6;首发时间&#xff1a;&#x1f339;2024年3月3日&…

【新书推荐】11.1 子程序设计

第十一章 子程序及参数传递 本章先讲述子程序设计的方法&#xff0c;然后介绍在子程序调用中参数的四种传递方法。 11.1 子程序设计 在前面的示例和练习中&#xff0c;会发现程序中会有一些反复使用到的代码片段。我们将程序中反复出现的程序片段设计成子程序&#xff0c;这样…

DM数据库学习之路(十九)DM8数据库sysbench部署及压力测试

sysbench部署 安装依赖 yum -y install make automake libtool pkgconfig libaio-devel vim-common 上传sysbench源代码 sysbench_tool.tar 测试是否安装成功 $ /opt/sysbench/sysbench-master-dpi/src/lua $ ./sysbench --version sysbench 1.1.0 sysbench测试DM 测试…

【STK】手把手教你利用STK进行仿真-STK软件基础02 STK系统的软件界面01 STK的界面窗口组成

STK系统是Windows窗口类型的桌面应用软件,功能非常强大。在一个桌面应用软件中集成了仿真对象管理、仿真对象属性参数、设置、空间场景二三维可视化、场景显示控制欲操作、仿真结果报表定制与分析、对象数据管理、仿真过程控制、外部接口连接和系统集成编程等复杂的功能。 STK…

MyBatis源码分析之基础支持层解析器

(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨ &#x1f440;&#x1f440;&#x1f440; 个人博客&#xff1a;小奥的博客 &#x1f44d;&#x1f44d;&#x1f44d;&#xff1a;个人CSDN ⭐️⭐️⭐️&#xff1a;传送门 &#x1f379; 本人24应届生一枚&#xff0c;技术和水平有限&am…

录制用户操作实现自动化任务

先上视频&#xff01;&#xff01; 流程自动化工具-录制操作绘制流程 这个想法之前就有了&#xff0c;趁着周末时间给它撸出来。 实现思路 从之前的文章自动化桌面未来展望中已经验证了录制绘制流程图的可行性。基于DOM录制页面操作轨迹的思路监听页面点击、输入事件即可&…

蓝桥杯练习题——二分

1.借教室 思路 1.随着订单的增加&#xff0c;每天可用的教室越来越少&#xff0c;二分查找最后一个教室没有出现负数的订单编号 2.每个订单的操作是 [s, t] 全部减去 d #include<iostream> #include<cstring> using namespace std; const int N 1e6 10; int d[…

Linux之相对路径、绝对路径、特殊路径符

相对路径和绝对路径 cd /root/temp 绝对路径写法 cd temp 相对路径写法 1、绝对路径&#xff1a;以根目录为起点&#xff0c;描述路径的一种写法&#xff0c;路径描述以 / 开头。 2、相对路径&#xff1a;以当前目录为起点&#xff0c;路径描述无需以 / 开头。 特殊路径符 如…

cRIO9040中NI9871模块的测试

硬件准备 CompactRIO9040NI9871直流电源&#xff08;可调&#xff09;网线RJ50转DB9线鸣志STF03-R驱动器和步进电机 软件安装 参考&#xff1a;cRIO9040中NI9381模块的测试 此外&#xff0c;需安装NI-Serial 9870和9871扫描引擎支持 打开NI Measurement&#xff06;Automa…

C++之set、multiset

1、set简介 set是一种关联式容器&#xff0c;包含的key值唯一&#xff0c;所有元素都会在插入时自动被排序&#xff0c;其存储结构为红黑树。set只能通过迭代器(iterator)访问。 set和multiset的区别&#xff1a; &#xff08;1&#xff09;set不允许容器中有重复的元素&…

C++_程序流程结构_选择结构_if

程序流程结构 C/C支持最基本的三种程序运行结构&#xff1a;顺序、选择、循环结构 顺序结构&#xff1a;程序按顺序执行&#xff0c;不发生跳转选择结构&#xff1a;依据条件是否满足&#xff0c;有选择地执行相应功能循环结构&#xff1a;依据条件是否满足&#xff0c;循环多…

跟 AI 学 StarRocks:简介

因为要支持公司的 BI 建设&#xff0c;团队引入了 StarRocks 数据库&#xff0c;此前我没有了解过此项技术&#xff0c;不过因为有架构师引入了此项技术栈&#xff0c;就顺便学习一下。 一、什么是 MPP 数据库&#xff1f; MPP 数据库指的是大规模并行处理&#xff08;Massiv…

zotero | 多平台同步 | 坚果云

zotero注册登陆 打开zotero软件&#xff0c;mac电脑打开首选项&#xff0c;如下图所示&#xff1a; 然后点击同步选项&#xff0c;如下图所示&#xff0c;如果已经有账号&#xff0c;请登陆账号&#xff0c;无则注册账号之后再登陆&#xff1b; 注册坚果云账号 注册完坚果…

QT6 libModbus 用于ModbusTcp客户端读写服务端

虽然在以前的文章中多次描述过,那么本文使用开源库libModbus,可得到更好的性能&#xff0c;也可移植到各种平台。 性能&#xff1a;读1次和写1次约各用时2ms。 分别创建了读和写各1个连接指针&#xff0c;用于读100个寄存器和写100个寄存器&#xff0c;读写分离。 客户端&am…