代码随想录训练营第三十六天 1049最后一块石头的重量II 494目标和

第一题:
原题链接:1049. 最后一块石头的重量 II - 力扣(LeetCode)

思路:

首先确认这是一道01背包问题的题目,如何转换:剩下尽可能小的重量,如何剩下呢?跟分割等和子集很像,就是将数组分为两个子集,这两个子集的元素之和相等则说明剩余重量最小,那么就是将数组的元素相加再除2,得到一个数值target,因为 / 是向下取整的,因此这个数值是较小的一个,所以所以sum - dp[target] 一定是大于等于dp[target]的

1.确认dp数组的含义:

dp[j]表示容量(这里说容量更形象,其实就是重量)为j的背包,最多可以背最大重量为dp[j]

可以回忆一下01背包中,dp[j]的含义,容量为j的背包,最多可以装的价值为 dp[j]。

相对于 01背包,本题中,石头的重量是 stones[i],石头的价值也是 stones[i] ,可以 “最多可以装的价值为 dp[j]” == “最多可以背的重量为dp[j]”

2.确认递推公式:

01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

本题则是:dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);

3.如何初始化

既然 dp[j]中的j表示容量,那么最大容量(重量)是多少呢,就是所有石头的重量和。

因为提示中给出1 <= stones.length <= 30,1 <= stones[i] <= 1000,所以最大重量就是30 * 1000。

而我们要求的target其实只是最大重量的一半,所以dp数组开到15000大小就可以了。

当然也可以把石头遍历一遍,计算出石头总重量 然后除2,得到dp数组的大小。

我这里就直接用15000了。

接下来就是如何初始化dp[j]呢,因为重量都不会是负数,所以dp[j]都初始化为0就可以了,这样在递归公式dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);中dp[j]才不会初始值所覆盖。

4.确认遍历顺序

如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!

代码如下:

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        vector<int> dp(15001);
        int sum = 0;
        for(int i = 0; i < stones.size(); i++){
            sum += stones[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]);
            }
        }
        //f(dp[target] == target) return 0;
        return sum - dp[target] - dp[target];
    }
};

第二题:
原题链接:494. 目标和 - 力扣(LeetCode)

思路:

如何转化为01背包问题呢。

假设加法的总和为x,那么减法对应的总和就是sum - x。

所以我们要求的是 x - (sum - x) = target

x = (target + sum) / 2

此时问题就转化为,装满容量为x的背包,有几种方法

这里的x,就是bagSize,也就是我们后面要求的背包容量。(target + sum) / 2 如果不能整除的话就是无解的,例如sum 是5,S是2的话其实就是无解的,同时如果 S的绝对值已经大于sum,那么也是没有方案的。

再回归到01背包问题,为什么是01背包呢?因为每个物品(题目中的1)只用一次!本题则是装满有几种方法。其实这就是一个组合问题了。

1.确认dp数组的含义:

dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法。

2.确认递推公式:

只要搞到nums[i],凑成dp[j]就有dp[j - nums[i]] 种方法。

例如:dp[j],j 为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[5]有多少方法呢,也就是把 所有的 dp[j - nums[i]] 累加起来。     

3.如何初始化

   从递推公式可以看出,在初始化的时候dp[0] 一定要初始化为1,因为dp[0]是在公式中一切递推结果的起源,如果dp[0]是0的话,递推结果将都是0。

4.遍历顺序   

对于01背包问题一维dp的遍历,nums放在外循环,target在内循环,且内循环倒序。

举例说明一下:

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

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

代码如下:

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int S) {
        int sum = 0;
        for (int i = 0; i < nums.size(); i++) sum += nums[i];
        if (abs(S) > sum) return 0; // 此时没有方案
        if ((S + sum) % 2 == 1) return 0; // 此时没有方案
        int bagSize = (S + sum) / 2;
        vector<int> dp(bagSize + 1, 0);
        dp[0] = 1;
        for (int i = 0; i < nums.size(); i++) {
            for (int j = bagSize; j >= nums[i]; j--) {
                dp[j] += dp[j - nums[i]];
            }
        }
        return dp[bagSize];
    }
};

第三题:

原题链接:474. 一和零 - 力扣(LeetCode)

思路:

1.确认dp数组的含义:dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]

2.确认递推公式:

dp[i][j]可以由前一个strs里的字符串推导出来。strs里的当前字符串里有zeroNum个0,oneNum个1。dp[i][j] 就可以是 dp[i - zeroNum][j - oneNum] + 1。

然后我们在遍历的过程中,取dp[i][j]的最大值。

所以递推公式:dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);

3.如何初始化

01背包的dp数组初始化为0就可以。

因为物品价值不会是负数,初始为0,保证递推的时候dp[i][j]不会被初始值覆盖。

4.确定遍历顺序

外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!

代码如下:

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0)); // 默认初始化0
        for (string str : strs) { // 遍历物品
            int oneNum = 0, zeroNum = 0;
            for (char c : str) {
                if (c == '0') zeroNum++;
                else oneNum++;
            }
            for (int i = m; i >= zeroNum; i--) { // 遍历背包容量且从后向前遍历!
                for (int j = n; j >= oneNum; j--) {
                    dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
                }
            }
        }
        return dp[m][n];
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于RAG大模型的变电站智慧运维-第十届Nvidia Sky Hackathon参赛作品

第十届Nvidia Sky Hackathon参赛作品 1. 项目说明 变电站是用于变电的设施&#xff0c;主要的作用是将电压转化&#xff0c;使电能在输电线路中能够长距离传输。在电力系统中&#xff0c;变电站起到了极为重要的作用&#xff0c;它可以完成电能的负荷分配、电压的稳定、容错保…

基坑安全:自动化监测系统的革新力量

在日新月异的基坑工程领域&#xff0c;基坑安全自动化监测系统犹如一位守护者&#xff0c;以其独特的优势&#xff0c;为工程的安全与质量保驾护航。该系统集先进的测量仪器、计算机技术与现代传感技术于一体&#xff0c;对基坑的围护结构及周边环境进行全方位、高精度的实时监…

【C++基础】初识C++(1)

目录 一、认识C 1.1 C 相关概念 1.2 C的发展 1.3 C的关键字 1.4 第一个程序 二、命名空间 2.1 namespace的定义 2.2 命名空间的使用 三、C输入和输出 四、缺省函数 五、函数重载 一、认识C 1.1 C 相关概念 1983年&#xff0c;Bjarne Stroustrup在C语⾔的基础上…

内网安全:权限维持的各种姿势

1.Linux权限维持 2.Windows权限维持 目录&#xff1a; 一.Linux权限维持&#xff1a; 1.webshell&#xff1a; 2.定时任务&#xff1a; 3.SUID后门&#xff1a; 4.SSH Key免密登录后门&#xff1a; 5.添加用户后门&#xff1a; 二.Windows权限维持 1.计划任务后门&…

NetSuite RPA技术实践

近期有同学提出一个需求。 “需要存取的報表是存貨分類帳(stock ledger)&#xff0c;將查到的各個[Item|Location]作為一組key&#xff0c;分別將報表中的「期末庫存量」「期末平均成本」「期末庫存量價值」這三欄的值&#xff0c;在每個月月底的時候自動將這個報表的這三欄數…

rollup打包工具

rollup打包工具 在学习vite和vue3源码的时候&#xff0c;接触到了rollup&#xff0c;所以过来学习一下 什么是rollup rollup是一个模块化的打包工具&#xff0c;会将javascript文件进行合并。比起webpack&#xff0c;webpack在打包的时候会进行代码注入(保障兼容性)&#xf…

位图——哈希思想的应用

三、位图 0、位图概念 所谓位图&#xff0c;就是用每一个比特位来存放某种状态&#xff08;0或1&#xff09;&#xff0c;是一种哈希思想的应用&#xff0c;适用于海量数据&#xff0c;整数&#xff0c;数据无重复的场景。通常是用来判断某个数据存不存在的。&#xff08;注意…

GaussDB DWS 详解

文章目录 GaussDB DWS 详解一、简介二、DWS的分布式架构架构概述关键组件 三、分布式查询数据查询流程SQL执行的示例 批注&#xff1a;本文引鉴了Forlogen博主的一些内容&#xff0c;并加以补充&#xff0c;以供学习了解。 GaussDB DWS 详解 一、简介 DWS(Data Warehouse Ser…

数据库-三范式

第一范式 1 数据库所有字段都只有单一属性。 2 单一属性由基本数据类型构成。 3 数据库的表都是二维的行与列。 例如上面的例子就不满足第一范式&#xff0c;因为是可以继续拆分的&#xff0c;拆分为更多的属性。 第二范式 1 符合第一范式 2 表必须有个主建 3 其它字段可以…

《0基础》学习Python——第十一讲__时间函数

一、时间函数是Python中的内置函数和模块&#xff0c;用于处理日期和时间相关的操作。以下是常用的时间函数的种类和用法&#xff1a; 1、time.time()&#xff1a;返回当前时间的时间戳。 时间戳&#xff08;timestamp&#xff09;是一种表示日期和时间的方式&#xff0c;它是一…

Linux--USB驱动开发(二)插入USB后的内核执行程序

一、USB总线驱动程序的作用 a&#xff09;识别USB设备 1.1 分配地址 1.2 并告诉USB设备(set address) 1.3 发出命令获取描述符 b&#xff09;查找并安装对应的设备驱动程序 c&#xff09;提供USB读写函数 二、USB设备工作流程 由于内核自带了USB驱动,所以我们先插入一个U…

CSS-0_3 CSS和单位

文章目录 CSS的值和单位属性值长度单位CSS和绝对单位CSS和相对单位百分比em & rem视口 颜色单位 碎碎念 CSS的值和单位 我们知道&#xff0c;CSS是由属性和属性值所组成的表 随着CSS的发展&#xff0c;属性不说几千也有几百&#xff0c;我从来不支持去背诵所有的可能性。…

K8S系列-Kubernetes基本概念及Pod、Deployment、Service的使用

一、Kubernetes 的基本概念和术语 一、资源对象 ​ Kubernetes 的基本概念和术语大多是围绕资源对象 Resource Object 来说的&#xff0c;而资源对象在总体上可分为以下两类: 1、某种资源的对象 ​ 例如节点 Node) Pod 服务 (Service) 、存储卷 (Volume&#xff09;。 2、…

Nginx入门到精通五(动静分离)

下面内容整理自bilibili-尚硅谷-Nginx青铜到王者视频教程 Nginx相关文章 Nginx入门到精通一&#xff08;基本概念介绍&#xff09;-CSDN博客 Nginx入门到精通二&#xff08;安装配置&#xff09;-CSDN博客 Nginx入门到精通三&#xff08;Nginx实例1&#xff1a;反向代理&a…

从0-1搭建一个web项目(页面布局详解)详解

本章分析页面布局详解详解 ObJack-Admin一款基于 Vue3.3、TypeScript、Vite3、Pinia、Element-Plus 开源的后台管理框架。在一定程度上节省您的开发效率。另外本项目还封装了一些常用组件、hooks、指令、动态路由、按钮级别权限控制等功能。感兴趣的小伙伴可以访问源码点个赞 地…

java数组之冒泡排序、快速排序

一、排序算法概述 1.算法定义 排序&#xff1a;假设含有n个记录的序列为{R1&#xff0c;R2&#xff0c;...,Rn},其相应的关键字序列为{K1&#xff0c;K2&#xff0c;...,Kn}。将这些记录重新排序为{Ri1,Ri2,...,Rin},使得相应的关键字值满足条Ki1<Ki2<...<Kin,这样的…

使用Keepalived实现双机热备(虚拟漂移IP地址)详细介绍

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f427;Linux基础知识(初学)&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; &#x1f510;Linux中firewalld防火墙&#xff1a;点击&#xff01; ⏰️创作…

BI工具的AI革新:对话式分析如何引领企业智能转型?

在数据驱动的时代&#xff0c;数据分析早已成为企业决策制定的关键支撑。但是&#xff0c;很多企业在数字化转型的过程中&#xff0c;常常面临门槛高、流程复杂等问题。而AI技术的发展为解决上述问题带来了突破。 为了简化企业智能转型路径&#xff0c;帆软接入AI大模型技术&a…

Scherlokk - Mac 文件快速搜索对比工具

Scherlokk 是一款适用于 Mac 的文件内容快搜比较工具&#xff0c;在 Scherlokk 内输入关键词&#xff0c;即可在本地磁盘 / 移动硬盘 / 网络驱动器等区域内&#xff0c;查找包含该词的文件&#xff0c;快速定位所需文件&#xff0c;并提供文件比较、快速筛选过滤等功能。 两种…

SpringCloud--常用组件和服务中心

常用组件 Euroke和nacos 区别 负载均衡 负载均衡策略有哪些 自定义负载均衡策略