【算法练习Day36】最后一块石头的重量 II目标和一和零

news2024/11/8 19:45:32

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:练题
🎯长路漫漫浩浩,万事皆有期待

文章目录

  • 最后一块石头的重量 II
  • 目标和
  • 一和零
  • 总结:

最后一块石头的重量 II

1049. 最后一块石头的重量 II - 力扣(LeetCode)
在这里插入图片描述

最后一块石头的重量II,这道题是将各个不同重量的石头相互碰撞,碰撞规则是如果两石头重量一样,那么两块石头均会撞碎,不会有剩余石头。如果其中一颗石头重量较大,那么会剩下较大重量石头减去较轻石头的重量,也就是说剩下一个新重量的石头,题目要求我们返回尽量小的剩余石头重量。

那么如何尽量使剩余的石头的重量最小呢?我们要做的就是将石头重量大致的平分成两堆,让两堆石头相撞,如果两堆石头总重量相等,那么剩余重量为0,如果不等,那么剩余的重量仍然为最小。这就是我们解题的一个思路。

动规五部曲的分析:

dp数组的含义:当前能承载的重量下能够存储的石头最大重量,我们假设将这一堆石头重量平分为两堆,所以最大的重量容量也就是总石头重量的一半。

递推公式:递推公式也就是借用01背包的模型,将该块石头放入背包或者不放入背包共两种不同的状态。和01背包的递推公式完全一样,这里的重量和价值均为石头的重量。

dp数组初始化:dp【0】初始化为0,因为能装总重量为0的背包,装不进石头。剩下的不为0的背包初始化为什么呢?根据之前的01背包的一维数组的初始化可知,依然初始化为0,因为我们要比较dp【j】的本身,如果初始化过大,就会导致本来应该赋值的量并不能赋值上。不懂得可以去看01背包的详解。

遍历顺序:遍历顺序就是正常的从前遍历石头,先遍历那一颗石头并不影响结果,背包是从后向前遍历的,不懂依然是往前翻01背包的一维数组解决方法,大多数例题我们都用一维数组解决。

打印:在未得到理想的答案时候,我们要使用打印dp数组的方法来辅助分析。

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        vector<int>dp(1501,0);
        dp[0]=0;int sum=0;
        for(auto i:stones)sum+=i;
        int target=sum/2;
        for(int i=0;i<stones.size();i++){
            for(int j=target;j>=stones[i];j--)
            dp[j]=max(dp[j],dp[j-stones[i]]+stones[i]);
        }
        return sum-dp[target]-dp[target];
    }
};

和我们上面的分析相同的思路,也就是说如果五部曲能完全懂,那么代码也十分容易,数组我们可以给定1501的大小,这是根据题意所得到的,+1是为了避免数组越界。

我们使用的方法是把全部重量的石头分为两半,最大的背包就是其总和一半,最后我们返回的是两堆石头碰撞剩余的部分,总和减去一半再减一半,有人会问了为什么要这样写呢?因为如果石头总重量不能均分两半,那么一定是会有非0的剩余,由于总和/2是向下取整所以一定是取得较小的数,我们这样做减法得到的就是剩余的新石头的重量。

目标和

494. 目标和 - 力扣(LeetCode)

在这里插入图片描述

目标和这道题我一看就丝毫没有思路,它有一点像是用回溯算法解决的题目,给定数组的每一个数都有取正和取负两种,然后最后算出共可以有多少次不同的方法凑得目标值。

但事实上是有可以用上01背包的思路的!思路有些不好想,具体思路是将要变成正数的部分和要变成负数的部分分开,正数部分加上那些应该是负数的部分,就可以得到目标值了。那么关键的来了,如何知道我们的左边正数部分应该取多少呢?它为多少时候我们才能加上右边部分凑成target呢?有以下公式推出,left-right=target这也就是说左边数字和右边数字相加就是目标值,为什么是减去呢?因为我们只是将右边看成是负数,其实并不是负数,我们将数组中正数逐个变成负数再放进负数堆里是很麻烦的,不是明智之举,所有我们直接减掉右边的正数就可以达成目的了。而left+right=sum也就是数组本身的数字逐个相加起来,那肯定就是总和sum了。这就可以推出right=sum-left,将该等式回带第一个式子得left=(sum+target)/2。这是个重要的式子,它帮助我们确定左边部分到底放多大,也就是背包最大容量是多大!sum可以求target是题目给的。

dp数组的含义:填满容量为j的背包共有多少种填充方法。

递推公式:递推公式的分析略显复杂,若j=5的情况下,给定数组{1,2,3,4,5},那么我们如果已经加入一个1,则需要dp【4】种方法凑成容量为5的背包,如果已经加入的数字是2,那么则需要dp【3】种方法才能够凑成容量为5的背包,以此类推如果加入的是数字5那么凑成容量为5背包需要dp【0】种,那么我们要求构成dp【5】共多少方法,也就是容量为5共多少种方法,那一定是前面的几种加在一起的和,则为构建的dp【5】的方法。就是dp【j-nums【i】】

而由于是累加在一起故递推公式是dp【j】+=dp【j-nums【i】】。

dp数组初始化:j为0时候初始化为1,这一点是和其他01背包题目初始化不同的地方,我们可以理解为目标值为0则有一种方法,不放入数组元素。事实上经过调试我们也可以知道,如果第一个位置初始化为0,那么累加的一直就是0了,无论target为多少,都无法出来其他数字了,所以一定要初始化为1。而其他j不等于0时候给它们初始化为0,这样方便第一次累加,实际上这和遍历顺序也有关联。

遍历顺序:遍历顺序是从左向右遍历物品,从后向前遍历背包,不懂看之前的文章。

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum=0;
        for(auto i:nums)sum+=i;
        if((target+sum)%2==1)return 0;
        int left=(target+sum)/2;
        if(abs(target)>sum)return 0;
        vector<int>dp(10001,0);dp[0]=1;
        for(int i=0;i<nums.size();i++){
            for(int j=left;j>=nums[i];j--){
                dp[j]+=dp[j-nums[i]];
            }
        }
        return dp[left];
    }
};

最后我们将dp【left】返回即可知道,我们为了凑成target共能有多少种方法。

一和零

474. 一和零 - 力扣(LeetCode)
在这里插入图片描述

这道题又是01背包的一种新的应用题型。这道题乍一看也不像是能用到01背包特性的。这道题有两个维度m和n控制着结果的产生,这意味着我们必须使用二维数组来表示,这和其他题目用一维数组是一样的,其他题目是用一维数组代替二维数组,这道题实际上使用二维数组代替三维数组。

dp数组及其含义:dp【i】【j】i个0j个1的最大子集大小为多少,该背包的最大容量是dp【m】【n】。

递推公式:递推公式是和一维数组的递推公式很类似,dp【i】【j】=max(dp【i】【j】,dp【i-x】【j-y】+1)。其中的x和y分别代表遍历当前物品时候,物品所含有的0数量和1数量。当当前背包的i和j对应的小于了x或者y中的任何一个,则跳出。

dp数组的初始化:初始化全都是0,第一个位置初始化,0个0,0个1装入不了任何的子集。

遍历顺序:仍然是物品从左到右依次遍历,这里我们是一个一个物品取,并且再嵌套一个循环来分解该物品有多少个0和多少个1。分解完毕了,我们走遍历背包,遍历背包依然是从后向前,并且这道题的二维背包,无论是先遍历0还是先遍历1效果都是一样的,没有先后之分。

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;
            for(char ch:str){
                if(ch=='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];                                                     
        }
};

相当于持续的更新dp【m】【n】,遍历不同的物品,在最大背包的容量之内,我们尽可能地装入更多的物品,也就是拥有给定数组尽可能多的数据(子集)。这里还要对递推公式做进一步的解释,就是为什么我们dp【i-x】【j-y】之后还要有一个+1的操作?我们初始化本来都是0,这里递推公式就是比较当前容量最大应该是当前所包含子集多,还是倒退一次再装入的多,每次进行第二个运算都要+1,意义是加入一个子集,所以我们要使自己数量+1,这和dp数组的定义也是密切相关的,数组就表示了当前状态下的最大子集数量。

我们来做一个对于01背包这些题型的总结:
我们之前做的最开始01背包,是在当前的背包最大容量内能够携带的最大价值是多少。

分割等和子集这道题是给定背包容量,看能不能装满背包,如果不能装满说明不能分割成等和子集。

最后一块石头的重量II是给定背包容量,尽可能装,看能装多少,最后一做差,其实和分割等和子集有一点相像。

目标和是给定背包容量看有多少种装满的方法。

一和零是一个二维背包,给定背包容量看最多能装多少不同的物品。

这些都是01背包的不同维度上的解决问题的典例。其中以后两道题是有一些难度的。

总结:

这一期三道题目是对于01背包不同层次的应用,各有特色,也各有难点。同时也是01背包的最后一期,下一期我们来学习完全背包。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

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

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

相关文章

2m照片用手机怎么照?三个方法随心选!

在用手机拍照的时候&#xff0c;我们会发现拍出的照片尺寸都很大&#xff0c;占用手机的存储空间较多&#xff0c;而自己又不需要如此高清晰度的照片&#xff0c;那么如何解决这个问题呢&#xff1f;下面介绍了三种方法。 方法一&#xff1a;调整手机拍照的设置选项 1、打开手…

Python---字符串切片-----序列名称[开始位置下标 : 结束位置下标 : 步长]

字符串切片&#xff1a;是指对操作的对象截取其中一部分的操作。字符串、列表、元组都支持切片操作。 本文以字符串为例。 基本语法&#xff1a; 顾头不顾尾&#xff1a; ----------类似range&#xff08;&#xff09; 范围&#xff0c;顾头不顾尾 相关链接Python----ran…

YOLOv5 - yolov5s.yaml 文件

基于深度学习的目标检测模型的结构:输入->主干->脖子->头->输出。主干网络提取特征&#xff0c;脖子提取一些更复杂的特征&#xff0c;然后头部计算预测输出。 YOLOv5网络结构主要由以下几部分组成: 骨干网络(Backbone) &#xff1a;Backbone:骨干网络&#xff0c…

JAVA虚拟机-第2章 Java自动内存管理-异常实践

Java堆溢出 堆的参数设置&#xff1a;将堆的最小值-Xms参数与最大值-Xmx参数设置 public class HeapOOM {static class OOMObject {}public static void main(String[] args) {List<OOMObject> list new ArrayList<OOMObject>();while (true) {list.add(new OO…

FRI及相关SNARKs的Fiat-Shamir安全

1. 引言 本文主要参考&#xff1a; Alexander R. Block 2023年论文 Fiat-Shamir Security of FRI and Related SNARKsAlbert Garreta 2023年9月在ZK Summit 10上分享 ZK10: Fiat-Shamir security of FRI and related SNARKs - Albert Garreta (Nethermind) 评估参数用的Sage…

【Git企业开发】第五节.远程操作

文章目录 前言一、理解分布式版本控制系统二、远程仓库 2.1 新建远程仓库 2.2 克隆远程仓库 2.3 向远程仓库推送 2.4 拉取远程仓库总结 前言 一、理解分布式版本控制系统 我们目前所说的所有内容(工作区&#xff0c;暂存区&#xff0c;版本库等等)&#x…

100G QSFP28 BIDI LR1光模块最新解决方案

上期文章我们有介绍到100G QSFP28 BIDI ER1 Lite光模块&#xff0c;本期内容我们将继续为大家介绍100G光模块系列的100G QSFP28 BIDI LR1光模块。这款产品同样也在易天ECOC光通讯展展出&#xff0c;下面跟着小易一起来看看吧&#xff01; 易天光通信的100G QSFP28 BIDI LR1单纤…

【Linux学习笔记】进程概念(中)

1. 操作系统的进程状态2. Linux操作系统的进程状态3. 僵尸进程4. 孤儿进程5. 进程优先级5.1. 优先级是什么和为什么要有优先级5.2. Linux中的进程优先级 6. 进程切换7. 环境变量7.1. 环境变量的认识7.2. 环境变量相关的命令7.3. 环境变量和本地变量7.4. 命令行参数7.5. 获取环境…

突破防火墙的一种方法

当Linux防火墙阻止来自某个ip的数据时&#xff0c;它应该是根据ip数据报里“源IP地址”字段取得的对方ip吧&#xff0c;那对方就不能通过篡改“源IP地址”来绕过防火墙吗&#xff1f;NAT模式下的路由器就修改了这个字段。 但这样的话&#xff0c;攻击者是收不到服务器返回的数…

通过内网穿透分享本地电脑上有趣的照片:部署piwigo网页

通过cpolar分享本地电脑上有趣的照片&#xff1a;部署piwigo网页 文章目录 通过cpolar分享本地电脑上有趣的照片&#xff1a;部署piwigo网页前言1.Piwigo2. 使用phpstudy网页运行3. 创建网站4. 开始安装Piwogo5. 设定一条内网穿透数据隧道6. 与piwigo网站绑定7. 在创建隧道界面…

k8s 多网卡方案multus

kubernetes 多网卡方案之 Multus_CNI 部署以及基本使用 一、multus cni 出现的背景 在k8s的环境中启动一个容器&#xff0c;默认情况下只存在两个虚拟网络接口&#xff08;loopback 和 eth0&#xff09;&#xff0c; loopback 的流量始终都会在本容器内或本机循环&#xff0c…

CSAPP BOMB LAB part2

bomb lab part2 phase3 汇编语法 switch 汇编版本 switch 例子: switch 使用 jump table movl 指令 cmpl指令是x86汇编语言中的一个比较指令&#xff0c;用于比较两个操作数的值。cmpl指令的格式如下&#xff1a; cmpl source, destinationsource和destination可以是…

为什么我电脑上C:\Windows\System32\config\regback文件夹是空的,怎么设置才能有备份文件

环境&#xff1a; Win10 专业版 19041 问题描述&#xff1a; 为什么我电脑上C:\Windows\System32\config\regback文件夹是空的&#xff0c;怎么设置才能有备份文件 解决方案&#xff1a; 微软说从 Windows 10 版本 1803 开始&#xff0c;系统注册表不再备份到 RegBack 文件…

第二章 线性表【数据结构与算法】【精致版】

第二章 线性表【数据结构与算法】【精致版】 前言版权第二章 线性表2.1 应用实例应用实例一 约瑟夫环问题(Josephus problem)应用实例二 一元多项式运算器 2.2 线性表的概念及运算2.2.1线性表的逻辑结构2.2.2 线性表的运算 2.3 线性表的顺序存储2.3.1 顺序表2.3.2 顺序表的基本…

网络安全进阶学习第二十一课——XXE

文章目录 一、XXE简介二、XXE原理三、XXE危害四、XXE如何寻找五、XXE限制条件六、XXE分类七、XXE利用1、读取任意文件1.1、有回显1.2、没有回显 2、命令执行&#xff08;情况相对较少见&#xff09;3、内网探测/SSRF4、拒绝服务攻击(DDoS)4.1、内部实体4.2、参数实体 八、绕过基…

制造企业如何三步实现进销存管理?

制造企业如何三步实现进销存管理&#xff1f; 一、什么是进销存软件&#xff1f; 进销存软件是一种针对制造业企业设计的管理软件系统&#xff0c;旨在协调和优化企业的生产、采购、销售以及库存管理等方面的活动。该系统的主要目标是提高企业的生产效率、降低库存成本、优化…

C++二分查找算法的应用:俄罗斯套娃信封问题

本文涉及的基础知识点 二分查找 题目 给你一个二维整数数组 envelopes &#xff0c;其中 envelopes[i] [wi, hi] &#xff0c;表示第 i 个信封的宽度和高度。 当另一个信封的宽度和高度都比这个信封大的时候&#xff0c;这个信封就可以放进另一个信封里&#xff0c;如同俄罗…

npm ERR! code ELIFECYCLE

问题&#xff1a; 一个老项目&#xff0c;现在想运行下&#xff0c;打不开了 npm install 也出错 尝试1 、使用cnpm npm install -g cnpm --registryhttps://registry.npm.taobao.org cnpm install 还是不行 尝试2、 package.json 文件&#xff0c;去掉 那个插件 chorm…

VS Code 开发 Spring Boot 类型的项目

在VS Code中开发Spring Boot的项目&#xff0c; 可以导入如下的扩展&#xff1a; Spring Boot ToolsSpring InitializrSpring Boot Dashboard 比较建议的方式是安装Spring Boot Extension Pack&#xff0c; 这里面就包含了上面的扩展。 安装方式就是在扩展查找 “Spring Boot…

​​​​​​​2022年上半年 软件设计师 上午试卷(33-68)

35 C 36 D 该题在2013年下半年考过类似的题目&#xff0c;从图中可见&#xff0c;页内地址的长度为12位&#xff0c;2124096&#xff0c;即4K&#xff0c;页号长度为21-12110&#xff0c;2101024&#xff0c;段号长度为31-22110&#xff0c;2101024。故正确答案为D。 37&#x…