算法训练营第四十三天||● 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

news2025/2/21 22:54:05

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

这道题和昨天的分割等和子集一样,只是最后返回值不一样

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int sum = 0;
        for(int i = 0;i<stones.size();i++){
            sum += stones[i];
        }
        int target = sum / 2;//将石头堆尽量分成重量相等的两堆
        vector<int> dp(1501,0);//容量为i的背包最大价值为dp[i] 最大重量也为dp[i]
        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];//总和减去两堆石头的最大重量即为返回值
    }
};

 ● 494. 目标和

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

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

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

x = (target + sum) / 2

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

这里的x,就是bagSize,也就是我们后面要求的背包容量。

大家看到(target + sum) / 2 应该担心计算的过程中向下取整有没有影响。

这么担心就对了,例如sum 是5,S是2的话其实就是无解的,所以:

(C++代码中,输入的S 就是题目描述的 target)
if ((S + sum) % 2 == 1) return 0; // 此时没有方案

同时如果 S的绝对值已经大于sum,那么也是没有方案的。

(C++代码中,输入的S 就是题目描述的 target)
if (abs(S) > sum) return 0; // 此时没有方案

再回归到01背包问题,为什么是01背包呢?

因为每个物品(题目中的1)只用一次!

这次和之前遇到的背包问题不一样了,之前都是求容量为j的背包,最多能装多少。

本题则是装满有几种方法。其实这就是一个组合问题了。

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

有哪些来源可以推出dp[j]呢?

只要搞到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]] 累加起来。

所以求组合类问题的公式,都是类似这种:

dp[j] += dp[j - nums[i]]

1

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

  1. dp数组如何初始化

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

这里有录友可能认为从dp数组定义来说 dp[0] 应该是0,也有录友认为dp[0]应该是1。

其实不要硬去解释它的含义,咱就把 dp[0]的情况带入本题看看应该等于多少。

如果数组[0] ,target = 0,那么 bagSize = (target + sum) / 2 = 0。 dp[0]也应该是1, 也就是说给数组里的元素 0 前面无论放加法还是减法,都是 1 种方法。

所以本题我们应该初始化 dp[0] 为 1。

可能有同学想了,那 如果是 数组[0,0,0,0,0] target = 0 呢。

其实 此时最终的dp[0] = 32,也就是这五个零 子集的所有组合情况,但此dp[0]非彼dp[0],dp[0]能算出32,其基础是因为dp[0] = 1 累加起来的。

dp[j]其他下标对应的数值也应该初始化为0,从递推公式也可以看出,dp[j]要保证是0的初始值,才能正确的由dp[j - nums[i]]推导出来。

  1. 确定遍历顺序

在动态规划:关于01背包问题,你该了解这些!(滚动数组) (opens new window)中,我们讲过对于01背包问题一维dp的遍历,nums放在外循环,target在内循环,且内循环倒序。

  1. 举例推导dp数组

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

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

dp数组状态变化如下:

C++代码如下

 

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = 0;
        for(int i = 0;i<nums.size();i++){
            sum += nums[i];
        }
        if(sum < abs(target)) return 0;
        if((sum + target)%2!=0){
            return 0;
        }
        int backsize = (sum + target) / 2;
        vector<int> dp(backsize+1,0);//容量为j的背包装满最多有dp[j]种方法
        dp[0] = 1;
        for(int i = 0;i<nums.size();i++){
            for(int j = backsize;j>=nums[i];j--){
                dp[j] += dp[j-nums[i]];
            }
        }
        return dp[backsize];
    }
};

 474.一和零

本题中strs 数组里的元素就是物品,每个物品都是一个!

而m 和 n相当于是一个背包,两个维度的背包

理解成多重背包的同学主要是把m和n混淆为物品了,感觉这是不同数量的物品,所以以为是多重背包。

但本题其实是01背包问题!

只不过这个背包有两个维度,一个是m 一个是n,而不同长度的字符串就是不同大小的待装物品。

开始动规五部曲:

  1. 确定dp数组(dp table)以及下标的含义

dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]

  1. 确定递推公式

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);

此时大家可以回想一下01背包的递推公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

对比一下就会发现,字符串的zeroNum和oneNum相当于物品的重量(weight[i]),字符串本身的个数相当于物品的价值(value[i])。

这就是一个典型的01背包! 只不过物品的重量有了两个维度而已。

  1. dp数组如何初始化

在动态规划:关于01背包问题,你该了解这些!(滚动数组) (opens new window)中已经讲解了,01背包的dp数组初始化为0就可以。

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

  1. 确定遍历顺序

在动态规划:关于01背包问题,你该了解这些!(滚动数组) (opens new window)中,我们讲到了01背包为什么一定是外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!

那么本题也是,物品就是strs里的字符串,背包容量就是题目描述中的m和n。

代码如下:

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);
        }
    }
}

有同学可能想,那个遍历背包容量的两层for循环先后循序有没有什么讲究?

没讲究,都是物品重量的一个维度,先遍历哪个都行!

  1. 举例推导dp数组

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

最后dp数组的状态如下所示:

474.一和零

以上动规五部曲分析完毕,C++代码如

 

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m+1,vector<int>(n+1,0));//二维dp数组均初始化为0 装满i个0j个1这么大的背包最多装dp[i][j]个物品
        for(auto st : strs){// 遍历物品
            int x = 0,y = 0;
            for(auto ch : st){//记录每个物品种0和1的个数分别为x和y  物品的重量就是x个0和y个1 
                if(ch == '0'){
                    x++;//0的个数
                }else{
                    y++;//1的个数
                }
            }
            for(int i = m;i>= x;i--){//遍历背包,两个维度 先是0方向的   背包的容量就是m个0和n个1
                for(int j = n;j>= y;j--){//再是1方向的
                    dp[i][j] = max(dp[i][j],dp[i-x][j-y]+1);//模仿01背包 表示最多多少个物品,所以是+1的操作
                }
            }

        }
        return dp[m][n];

    }
};

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

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

相关文章

结构型模式 - 享元模式

概述 定义&#xff1a; 运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似对象的开销&#xff0c;从而提高系统资源的利用率。 结构 享元&#xff08;Flyweight &#xff09;模式中存在以下两种状态&…

Python案例之新浪世界杯各国球队数据(德国VS日本)

目录标题 前言知识点:开发环境:实现代码:代码展示尾语 前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 知识点: 动态数据抓包 requests发送请求 json数据解析 开发环境: python 3.8 运行代码 pycharm 2021.2 辅助敲代码 requests pip install requests 第三方模块…

linux系统上安装R语言并安装mclust包

请注意&#xff0c;如果你本来就是root账号&#xff0c;则所有的sudo都不用加。 x.1 安装R语言 安装R语言建议使用清华源&#xff0c;链接https://mirrors.tuna.tsinghua.edu.cn/CRAN/bin/linux/ubuntu/ 把下面这一串代码在terminal中全部输入便可&#xff0c;5000个R包也建…

分类管理业务开发 -- 手把手教你做ssm+springboot入门后端项目黑马程序员瑞吉外卖(四)

文章目录 前言一、开发功能预览二、公共字段自动填充1.问题分析2.代码实现3.功能测试4.功能完善 三、新增分类1.需求分析2.数据模型3.代码开发4.功能测试 四、分类信息分页查询1.需求分析2.代码开发3.功能测试 五、删除分类1.需求分析2.代码开发3.功能测试4.功能完善 六、修改分…

VS2013配置所有项目附加包含目录的办法

任意打开一个项目&#xff0c;点击视图->其他窗口->属性管理器 在属性管理器中打开Debug|Win32&#xff0c;找到Microsoft.Cpp.Win32.user&#xff0c;双击打开 直接配置VC的附加包含目录就可以了 之后所有项目都会继承这些目录 这样就不用为每个项目配置库包含目录了…

[微信小程序] 关于自定义字体的坑

报错&#xff1a; [渲染层网络层错误] Failed to load local font resource... the server responded with a status of 500 (HTTP/1.1 500 Internal Server Error) ... 原因&#xff1a;小程序不允许引用本地ttf等字体文件 解决办法&#xff1a;改成网络引用&#xff0c;或者…

通过xshell连接服务器后出现中文乱码的解决方法

先查看服务器环境变量中设置的是什么字符集&#xff0c;命令为&#xff1a;locale 然后在xshell工具中把字符集设置为上面查出来的 然后关掉xshell工具再重新打开。

Python SMTP发送邮件

如何使用Python发送QQ邮件&#xff1f;如何发送带附件的邮件&#xff1f;这篇文章将详细说明 目录 一、发送邮件 二、发送HTML格式的邮件 三、在HTML中添加图片 四、发送带附件的邮件 五、最终整合版 六、配置指引 一、发送邮件 import smtplib from email.mime.text im…

疑问:为什么我的手机不能同时放两张电信卡呢?联通移动可以

很多后台的小伙伴私信我&#xff1a;“为什么我的双卡双待手机不能用两张电信卡呢&#xff1f;”其实我一直在认真的去查证这个问题&#xff0c;因为现在普遍网上的大流量手机卡套餐&#xff0c;电信是主力&#xff0c;如果第一张卡是电信&#xff0c;第二张卡不能使用电信了&a…

物联网大数据传输安全难题与解决方案

随着物联网时代的到来&#xff0c;大数据传输变得更加频繁和庞大&#xff0c;同时也给传输安全带来了更高的风险和挑战。本文将探讨物联网时代的大数据传输安全问题&#xff0c;并介绍镭速传输如何有效地解决这些问题。 首先&#xff0c;物联网时代的大数据传输面临的一个主要问…

查看IP地址方法(电脑IP地址方法)

查看IP地址方法 如何识别win7还是win10系统&#xff1f; &#xff08;一&#xff09;Win7系统电脑导航栏如下&#xff1a; &#xff08;二&#xff09;Win10系统电脑导航栏如下&#xff1a; 一、win7系统查看IP地址 方法一&#xff1a;查看网络设置 点击电脑导航栏最右下…

中间件上云部署 rocketmq

中间件上云部署 rocketmq rocketmq部署一、rokectmq介绍二、rokectmq特性三、使用rocketmq理由四、rocketmq 核心概念五、rocketmq角色六、rocketmq集群部署方式七、rocketmq集群部署7.1 环境说明7.2 构建rocketmq镜像7.3 获取rocketmq-dashboard镜像7.4 rocketmq部署描述文件编…

ROS学习——常用API

一、初始化 1.作用 ROS初始化函数 2.参数列表 argc------------封装实参的个数&#xff08;n1&#xff09; argv------------封装参数的数组 name----------为 节点命名&#xff0c;需要保证其唯一性 options---------节点启动选项 返回值&#xff1a;void 3.使用细节 …

超低输入电压升压电路解决方案

便携式产品一般都采用电池供电&#xff0c;而因为成本和体积方面的考虑&#xff0c;在设计上有减少使用电池数量及体积的趋势。另外&#xff0c;亦因全球能源问题&#xff0c;各种各类的电池使用已备受关注了。当中包括太阳能电池及燃料电池。 而这样就会影响到电源电压比设备所…

人工智能革命|是疯狂炒作还是大势所趋?

近期关于人工智能的话题与炒作激增。如果你看看过去五年“AI”一词的搜索量&#xff0c;就会发现它一直停滞&#xff0c;直到2022年11月30日&#xff0c;OpenAI 凭借 ChatGPT 引发了人工智能革命。 Google 趋势 — 过去 5 年“AI”搜索量 短短六个月内&#xff0c;究竟发生了…

系统学习Linux-搭建基础服务器实验集合

实验分析 主机DHCP分配静态253地址&#xff0c;需配置网关主机DNF静态分配252地址域名机dhcp自动分配地址要求251中继主机添加成两块网卡并配置两个网段的网卡地址DNS解析域名并把客户机251装apache、tomcat、ngnix并把根目录设置成web下 一、搭建DHCP服务器 vm1网卡 配置网…

「硬核」实操如何拥有一个自己的数字人模型

一、前言 近年来&#xff0c;随着人工智能技术&#xff0c;VR&#xff0c;元宇宙等技术的发展&#xff0c;数字人&#xff08;Digital Human&#xff09;逐渐成为研究的热点之一&#xff0c;数字人是指通过计算机技术模拟出的具有人类外表&#xff0c;动作和语言能力的虚拟人物…

【想要学习适当技能来处理复杂数据科学项目和“用数据思考”?看《现代数据科学(R语言·第2版)》就对了】

《现代数据科学(R语言●第2版)》是面向本科生的综合性数据科学教材&#xff0c;通过结合使用统计和计算方式来解决现实中的数据问题。本书不仅专注于案例或编程语法&#xff0c;还讲述如何利用最新R/RStudio计算环境中的统计编程&#xff0c;从各种数据中提取有意义的信息&…

Jmeter性能测试通过插件监控服务器资源使用情况

Jmeter作为性能测试的首选工具&#xff0c;那么在性能测试过程中如何方便快捷的监测服务器资源使用情况&#xff1f; 可以通过jmeter 安装"PerfMon(Servers Performance Monitoting)"插件并配合服务端资源监控工具进行实现&#xff0c;详细操作流程如下&#xff1a;…

微服务部署架起App运维的高速通道

今天来说下微服务&#xff0c;我们知道微服务在 App 开发中具备模块化开发、独立部署扩展、问题隔离等特点&#xff0c;这种微服务架构模式能够使应用程序更具弹性、可扩展和可维护&#xff0c;能够更好地应对快速变化的需求和规模的增长。 准备通过系统的梳理说一说微服务部署…