代码随想录算法训练营第三十七天|1049. 最后一块石头的重量 II ,494. 目标和,474.一和零

1049. 最后一块石头的重量 II - 力扣(LeetCode)

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

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

  • 如果 x == y,那么两块石头都会被完全粉碎;
  • 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x

最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0

示例 1:

输入:stones = [2,7,4,1,8,1]
输出:1
解释:
组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。

思路:第一步:本题如何转换成背包问题;第二步转换成背包问题之后,哪些是重量哪些是价值;

①这里注意到题目中x==y将完全粉碎,完全粉碎相较于x!=y,剩下的石头重量肯定最小,所以从结果来看,将stones分成两堆重量接近甚至相等的石头,碰撞之后会使剩下石头最小甚至没有剩下。

②背包问题中的价值也就是这里石头重量之和,我们要使装石头的重量等于全部石头的一半,遍历才会停止。背包问题中的重量相当于每个石头的重量。

解决:动态规划五步曲

        1.确定dp[i]的含义;

        j表示我们要装j重量的石头,j最大等于目标值;dp[j]表示当前目标是j重量情况下,能满足的最大石头重量和

        这里有点绕,可以举例说明一下,例如有三个石头2,7,4,dp[9]和dp[10]其实都等于2+7,因为如果加上4,重量会超过我们要求的目标值10,实际上dp[9]到dp[12]都等于2+7,但如果目标值是13,dp[13]=2+7+4。

        2.确定递推公式;

        经过上步分析我们已经知道了,dp[j]当前最大的重量其实来自于两种情况:①加上石头i,②不加上石头i,这又和之前题目类似。

        dp[j]=max(dp[j],dp[j-stones[i]]+stones[i]);

        3.dp数组初始化;    

        因为提示中给出1 <= stones.length <= 30,1 <= stones[i] <= 1000,所以最大重量就是30 * 1000 。而我们要求的target其实只是最大重量的一半,所以dp数组开到15000大小就可以了。

        vector<int> dp(15001,0)

        4.确定遍历顺序;

        遍历顺序和背包问题一维数组一样,从后向前遍历,防止重复包含。

        5.举例推导dp。

        输入:[2,4,1,1],此时target = (2 + 4 + 1 + 1)/2 = 4

代码:注意返回值是sum减去两个dp[target]

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        vector<int> dp(15001,0);
        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]);
            }
        }
        return sum-dp[target]-dp[target];
    }
};

494. 目标和 - 力扣(LeetCode)

给你一个非负整数数组 nums 和一个整数 target 。

向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :

  • 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例 1:

输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3

思路:如何将本题转换成背包问题

        目标targret由nums里面元素加或者减运算得出,所以我们将结果分为两个集合;一种里面都是加元素,一种都是减元素。

        例如-1 + 1 + 1 + 1 + 1 = 3加法集合里是nums[1]到nums[4],减法集合里是nums[0];

        设加法集合里元素和是x,那减法集合里元素和是sum-x;(sum是nums里全部元素和);

        目标值等于加法集合元素和减去减法集合元素和;target=x-(sum-x)

        最后x=(sum+target)/2,此时问题就转化为,装满容量为x的背包,有几种方法。(这一步很重要!)。这里再解释一下,只要从nums中找到元素使其的和等于x,那么nums中剩下的元素在计算target时减去,最后结果就是target。

解决:动态规划五步曲

        1.确定dp[j]的含义;

        首先确定j,j表示和是j,也就是背包问题里的容量,j从小到x;dp[j]就表示组成和是j的方法数量

        2.确定递推公式;

        如果我们要用若干个元素组成和为j的方案数,那么有两种选择:不选第i个元素或者选第i个元素。如果不选第i个元素,那么原来已经有多少种方案数就不变;如果选第i个元素,那么剩下要组成和为j - nums[i] 的方案数就等于dp[j - nums[i]]。所以两种选择相加就是dp[j]。

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

        3.dp数组初始化;   

        考虑极端情况,如果j=0时候,数组[0],此时方法只有1种,所以dp[0]=1;注意如果数组[0,0,0,0,0],j=0时,dp[0]并不等于1, 此dp[0]非彼dp[0],五个0组成算式等于0的方法是从初始的dp[0]=1累加起来的。没有初始化dp[0]=1,结果都会是0。

        4.确定遍历顺序;

        由于每次更新dp[j]都依赖于之前计算过得dp值(也就是说当前行依赖于上一行),所以我们必须从后往前遍历更新dp值(也就是说从右往左更新),否则会覆盖掉之前需要用到得值。

        5.举例推导dp。

输入: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 target) {
        int sum=0;
        for(int i=0;i<nums.size();i++){
            sum+=nums[i];
        }
        if(target>sum||(target)<(-sum)) return 0;//目标值大于总和或者小于负总和,不存在
        if ((target + sum) % 2 == 1) return 0; // 此时没有方案
        int x=(sum+target)/2;
        vector<int> dp(x+1,0);//这里需要x+1,因为0也要算
        dp[0]=1;
        for(int i=0;i<nums.size();i++){
            for(int j=x;j>=nums[i];j--){
                dp[j]+=dp[j-nums[i]];
            }
        }
        return dp[x];
    }
};

474. 一和零 - 力扣(LeetCode)

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。

请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

示例 1:

输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
输出:4
解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。
其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。

思路:转换成01背包问题,搞清楚谁是背包,谁是物品,最大子集在背包问题中是什么?

        物品:每个元素都有1和0,1和0的个数就代表该物品属性;

        背包:我们知道物品是元素,那元素要放在子集里,所以子集是背包,以往我们都知道背包有容量,这里子集也“容量”,变成了m和n,也就是说装的元素含有1的个数不超过n,有1的个数不超过m;容量变成了n和m,那背包所装物品的价值就是子集的长度,问题也就是求子集的最大长度转换成了背包所装物品的最大价值

解决:动态规划五步曲

        1.确定dp[i][j]的含义;

        i这里指0的数量,j这里指1的数量,最后dp[i][j]就是表示子集的元素个数。

        2.确定递推公式;

        获得dp[i][j]同样有两种方式,加入当前元素,dp[i-zero][j-one]+1,或者不加dp[i][j];zero代表0的个数,one代表1的个数,并且是指当前遍历的的元素。

        dp[i][j]=max(dp[i][j],dp[i-zero][j-one]+1)

        3.dp数组初始化; 

         没装元素前,0和1个数以及子集长度都是0,初始化就是dp[i][j]=0。

        4.确定遍历顺序;

        还是从后向前遍历,注意这里i和j都需要从后向前遍历,防止元素重复加入导致0和1的个数变大。

        5.举例推导dp。

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

        注意这里和二维背包并不相同,i和j都是要考虑的“容量”

代码:

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 zero=0;int one=0;
            for (char c : str) {//统计元素中0和1的个数
                if (c == '0') zero++;
                else one++;
            }
            for (int i = m; i >= zero; i--) { // 遍历背包容量且从后向前遍历!
                for (int j = n; j >= one; j--) {
                    dp[i][j] = max(dp[i][j], dp[i - zero][j - one] + 1);
                }
            }
        }
        return dp[m][n];
    }
};

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

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

相关文章

前端Flex布局的常用属性及其应用场景

目录 学习目标&#xff1a; 学习内容&#xff1a; 什么是flex布局&#xff1f; 如何使用flex布局&#xff1f; 容器属性 项目属性 flex布局有哪些主要的属性&#xff1f; flex布局的优缺点是什么&#xff1f; 学习时间&#xff1a; 最后总结&#xff1a; 学习目标&am…

医院信息系统源码,采用JAVA编程,支持跨平台部署应用,满足一级综合医院(专科二级及以下医院500床)的日常业务应用

医院HIS系统源码&#xff0c;HIS系统全套源码&#xff0c;支持电子病历4级&#xff0c;自主版权 his医院信息系统内设门诊/住院医生工作站、门诊/住院护士工作站。各工作站主要功能依据职能要求进行研发。如医生工作站主要功能为编辑电子病历、打印、处理医嘱&#xff1b;护士工…

虾皮关键词工具:优化您的Shopee商品曝光度和搜索排名

在Shopee平台上&#xff0c;关键词工具对于提高商品曝光度和搜索排名非常重要。本文将向您介绍一些值得推荐的关键词工具&#xff0c;这些工具可以帮助您找到合适的关键词以优化您的商品列表&#xff0c;并提高搜索排名和曝光度。 先给大家推荐一款shopee知虾数据运营工具知虾免…

读者和写者问题

它可以解决的问题&#xff1a; 可以支持多个读者访问&#xff0c;通过count计数 来实现多个读者访问的时候是互斥的&#xff0c;不会出现不符合进程同步的问题&#xff1a;设置mutex互斥锁&#xff0c;保证count或count--和if Pv(mutex)是一气呵成的 读写公平&#xff0c;通过…

软件工程之UML建模

从公众号转载&#xff0c;关注微信公众号掌握更多技术动态 --------------------------------------------------------------- 一、建模基础 1.建模的底层逻辑 用一个公式表达建模的底层逻辑&#xff1a;建模 图形 逻辑 现实的抽象&#xff0c;用一句概括即是用图形逻辑…

一张图理解接口测试框架

测试框架先向测试数据库中插入测试数据&#xff08;如&#xff1a;name”Tom“&#xff09; 调用被测系统提供的接口&#xff08;传参&#xff1a;name”Tom“&#xff09; 从测试数据库中查到符合参数的数据 将查询到的数据组成Json格式&#xff0c;并返回给测试框架 提供…

添加新公司代码的配置步骤-Part4

原文地址&#xff1a;配置公司代码 概述 这是一系列讨论和列出向系统添加新公司代码时必须完成的事务的四篇博客中的最​​后一篇。以下是这四个文档涵盖的主题列表&#xff1a; 企业结构 - 第 1 部分 FI 配置 – 第 2 部分 SD 配置 – 第 3 部分 物流 – 概述 – 第 3 部分…

SpringBoot集成系列--ElasticJob

文章目录 一、集成步骤1、添加 ElasticJob 的依赖2、配置 ElasticJob3、定义Job 二、ElasticJob-UI三、Elastic-Job分片理解四、原理 一、集成步骤 1、添加 ElasticJob 的依赖 引入相关依赖到pom.xml <!-- Elastic-Job --> <dependency><groupId>org.apac…

随笔-这都是命吗

我与鹏哥、小付有个小群&#xff0c;前几天&#xff0c;鹏哥在群里发了一个图&#xff0c;是他那个城市准备扶持的高新产业&#xff0c;有元宇宙、量子信息、生物制药、人工智能什么的。 先前的时候鹏哥给我说过&#xff0c;当地准备了六百多亩地&#xff0c;准备发展高新产业…

模块化机房在大数据时代的角色:高效、可扩展的数据存储和处理平台

随着大数据时代的到来&#xff0c;数据已经成为企业竞争的核心资源。然而&#xff0c;传统的数据中心已经无法满足现代业务的需求&#xff0c;尤其是在数据存储和处理方面。模块化机房作为一种新型的数据中心建设模式&#xff0c;具有高效、可扩展等优势&#xff0c;逐渐成为大…

linux加速访问github的方法(2023.12.2)

本文通过修改hosts文件的方法实现加速访问github 本文查询的GitHub域名映射的ip地址时间为2023.12.2&#xff0c;建议大家先查询域名对应的IP是否有变化 查询方法 进入网址&#xff1a;IP/IPv6查询&#xff0c;服务器地址查询 - 站长工具快速查询用户的IP和浏览器、操作系统…

【Hung-Yi Lee】强化学习笔记

文章目录 What is RLPolicy GradientPolicy Gradient实际是怎么做的On-policy v.s. Off-policyExploration配音大师 Actor-Critic训练value function的方式网络设计DQN Reward ShapingNo Reward&#xff1a;Learning from Demonstration What is RL 定义一个策略网络&#xff0…

一则广告,一个故事,这就我选择学习计算机专业的两个原因

还记得当初自己为什么选择计算机&#xff1f; 现在回想起来&#xff0c;当初驱使自己选择学习计算机专业的原因&#xff0c;一共有两个&#xff1a; 一、一则长城电脑的广告。 上个世纪80年代&#xff0c;我还在读小学&#xff0c;当时在中央电视台上经常播放着的长城电脑的一则…

二十一章(网络通信)

计算机网络实现了多台计算机间的互联&#xff0c;使得它们彼此之间能够进行数据交流。网络应用程序就是在已连接的不同计算机上运行的程序&#xff0c;这些程序借助于网络协议&#xff0c;相互之间可以交换数据。编写网络应用程序前&#xff0c;首先必须明确所要使用的网络协议…

05 硬件知识入门(三极管)

1 三极管简介 三极管又称晶体三极管&#xff0c;是一种具有放大功能的半导体器件。图6-1&#xff08;a&#xff09;所示是一些 常见的三极管实物外形&#xff0c;三极管的图形符号如图6-1&#xff08;b&#xff09;所示。 1. 三极管引脚的基本介绍 三极管通常有三个引脚&…

二叉树的层平均值[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[3.00000,14.50000,1…

postman实现接口自动化图解步骤,测试用例集,断言,动态参数,全局变量的随笔记录

实现接口自动化的方式有很多种&#xff0c;requests unittest ddt 的接口自动化框架有些朋友也有接触&#xff0c;但是考虑到很多没有代码基础&#xff0c;且这种框架实现需要的时间周期比较长&#xff0c;但是大多数公司的项目时间并不充裕。 这篇随笔主要就是记录实现效率…

如何解决5G基站高能耗问题?

安科瑞 须静燕 截至2023年10月&#xff0c;我国5G基站总数达321.5万个&#xff0c;占全国通信基站总数的28.1%。然而&#xff0c;随着5G基站数量的快速增长&#xff0c;基站的能耗问题也逐渐日益凸显&#xff0c;基站的用电给运营商带来了巨大的电费开支压力&#xff0c;降低5…

网络机房的功能有哪些?

网络机房的功能主要包括&#xff1a; 信息存储和管理&#xff1a;机房作为信息系统的核心&#xff0c;需要提供可靠的存储和管理能力&#xff0c;包括服务器、存储设备、备份系统等硬件设备&#xff0c;以及数据备份、数据迁移、容灾等管理方法和技术。网络连接和通信&#xf…

202350读书笔记|《再别康桥:徐志摩诗选》——微风起,清芬酝藉,不减荼

202350读书笔记|《再别康桥&#xff1a;徐志摩诗选》——微风起&#xff0c;清芬酝藉&#xff0c;不减荼 《再别康桥&#xff1a;徐志摩诗选》我觉得有时候诗人是很狂热的&#xff0c;上头的感觉。 有几首很喜欢&#xff0c;节选如下&#xff1a; 偶然 我是天空里的一片云&…