Leetcoder Day38| 动态规划part05 背包问题

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

有一堆石头,每块石头的重量都是正整数。

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

如果 x == y,那么两块石头都会被完全粉碎;

如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。

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

示例:

  • 输入:[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],这就是最优值。

提示:

  • 1 <= stones.length <= 30
  • 1 <= stones[i] <= 1000

本题要求最小的石头重量,最好的情况就是最后剩下的两个石头重量一致,结果为0。那也就跟昨天的分割子集的本质一样,将这个数组分割成两个子集,使得两个子集的元素和相等。因此看是否可以将石头重量集合拆分为总和为sum/2的子集。因为本题石头粉碎是不可逆的,因此属于01背包问题,那么就开始对应如下四点:

  • 背包的可容纳的重量为sum / 2
  • 背包要放入的石头的重量也就是石头的价值
  • 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
  • 背包中每一个元素是不可重复放入

动规五部曲:

  1. 确定dp数组以及下标的含义:dp[j]表示重量为j的背包,最多可以背的重量为dp[j]
  2. 确定递推公式:dp[j]=max(dp[j], dp[j-stones[i]]+stones[i])
  3. dp数组如何初始化:sum+=stones[i] target=sum/2
  4. 递归顺序:先遍历石头,再遍历重量,并且重量要倒序遍历

如果背包需要满足的容量为target,当dp[target]==target时,背包就装满了,也就是本题的结果为0。如果不能满足,因为sum/2是向下取整,所以sum-dp[target]一定大于dp[target],所以相撞以后剩下的石头重量为(sum-dp[target])-dp[target]

class Solution {
    public int lastStoneWeightII(int[] stones) {
        int sum=0;
        for(int i=0;i<stones.length;i++){
            sum+=stones[i];
        }
        int target=sum>>1;
        int[] dp= new int[target+1];
        for(int i=0;i<stones.length;i++){
            for(int j=target;j>=stones[i];j--){
                dp[j]=Math.max(dp[j], dp[j-stones[i]]+stones[i]);
            }
        }
        return (sum-dp[target])-dp[target]; 
    }
}

注意:这里不需要再单独判断一下dp[target]是否等于target了,如果等于的话,其实最后相当于sum-2*target=0了,如果多写了这一步判断,反而会漏算情况。

并且sum/2的空间复杂度要比sum>>1,移位运算高,所以最好写后者。

494.目标和

给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。

返回可以使最终数组和为目标数 S 的所有添加符号的方法数。

示例:

  • 输入:nums: [1, 1, 1, 1, 1], S: 3
  • 输出:5

解释:

  • -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

一共有5种方法让最终目标和为3。

提示:

  • 数组非空,且长度不会超过 20 。
  • 初始的数组的和不会超过 1000 。
  • 保证返回的最终结果能被 32 位整数存下。

这道题先用动态规划五部曲想了一下:本题依然是只能取一次,所以还是01背包思路

  1. 确定dp数组以及下标的含义:dp[j]表示达到和为j的值有dp[j]种方法
  2. 确定递推公式:目前还不知道
  3. dp数组如何初始化:dp[0]=1,因为当只有1个元素的时候,那么就只有一种方法
  4. 确定遍历顺序:还是按照元素从前向后,按照数值从后向前
  5. 举例推导dp数组:递推公式还没出来,暂时举不出来例子

脑子比较累,直接看了题解:

本题要如何使表达式结果为target。首先因为有sum,所以left + right = sum,sum是固定的,因此right = sum - left。既然为target,那么就一定有  left组合 - right组合 = target,这里left就是加法的总和,right就是减法的总和,公式来了, left - (sum - left) = target 推导出 left = (target + sum)/2, target是固定的,sum是固定的,left就可以求出来。此时问题就是在集合nums中找出和为left的组合。此时问题就转化为,装满容量为left的背包,有几种方法。还要注意几种特殊的情况:(target + sum) / 2 应该担心计算的过程中向下取整有没有影响,如果sum为5,target为2,那么无论怎样也不会到达target值,也就是说当sum+target为奇数时,是没有解决方案的。并且如果target的的绝对值大于sum,也是没有解决方法的,直接返回0。

只要搞到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]]

import java.lang.Math;
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum=0;
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
        }
        int left=(sum+target)>>1;
        if((sum+target)%2==1) return 0;
        if(Math.abs(target)>sum) return 0;
        int[] dp= new int[left+1];
        dp[0]=1;
        for(int i=0;i<nums.length;i++){
            for(int j=left;j>=nums[i];j--){
                dp[j]+= dp[j-nums[i]];
            }
        }
        return dp[left];
    }
}

474.一和零

给你一个二进制字符串数组 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 。

示例 2:

  • 输入:strs = ["10", "0", "1"], m = 1, n = 1
  • 输出:2
  • 解释:最大的子集是 {"0", "1"} ,所以答案是 2 。

提示:

  • 1 <= strs.length <= 600
  • 1 <= strs[i].length <= 100
  • strs[i] 仅由 '0' 和 '1' 组成
  • 1 <= m, n <= 100

本题还是一个背包问题,本题中strs 数组里的元素就是物品,每个物品都是一个,只能取一次,因此还是01背包问题。这里限制了两个元素的大小,这两个大小之间是没有什么制约关系的,相当于有两个背包,所以要定义一个二维dp数组dp[i][j]继续开始动规五部曲:

  1. 确定dp数组以及下标的含义:dp[i][j]表示最多取i个1和j个0后的最大子集的大小
  2. 确定递推公式:dp[i][j]是由前一个已经选好的子串推导而来,假设前面那个子串已经有zero个0和one个1,那么dp[i][j]=dp[i-zero][j-one]+1,并且还要跟自己做比较,取最大值。
  3. dp数组如何初始化:初始化为0
  4. 确定遍历顺序:遍历物品要从前往后,遍历背包要从后往前,这里m和n都是背包,所以都是从后往前遍历。
  5. 举例推导dp数组:以输入:["10","0001","111001","1","0"],m = 3,n = 3为例,最后dp数组的状态如下所示:
     

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m+1][n+1];
        for(String str:strs){
            int zero=0, one=0;
            for(char c : str.toCharArray()){
                if(c =='0') zero++;
                else one++;
            }
            for(int i=m;i>=zero;i--){
            for(int j=n;j>=one;j--){
                dp[i][j]=Math.max(dp[i][j], dp[i-zero][j-one]+1);
            }
        }
        }
        return dp[m][n];
    }
}

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

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

相关文章

云端技术驾驭DAY15——ClusterIP服务、Ingress服务、Dashboard插件、k8s角色的认证与授权

往期回顾&#xff1a; 云端技术驾驭DAY01——云计算底层技术奥秘、云服务器磁盘技术、虚拟化管理、公有云概述 云端技术驾驭DAY02——华为云管理、云主机管理、跳板机配置、制作私有镜像模板 云端技术驾驭DAY03——云主机网站部署、web集群部署、Elasticsearch安装 云端技术驾驭…

Java中继承的作用及解析

在 Java 中&#xff0c;继承是一种非常重要的面向对象编程特性。它的主要作用包括以下几个方面&#xff1a; 代码复用&#xff1a;通过继承&#xff0c;子类可以复用父类的代码&#xff0c;包括属性和方法。这样可以避免重复编写相同的代码&#xff0c;提高代码的复用性和可维护…

keycloak-鉴权springboot

一、环境描述 keycloak鉴权springboot的方式&#xff0c;此处简单介绍&#xff0c;springboot官方也提供了demo https://github.com/keycloak/keycloak-quickstarts/tree/latest/spring/rest-authz-resource-server 以及文档说明 Securing Applications and Services Guide…

2024年智能驾驶年度策略:自动驾驶开始由创造型行业转向工程型行业

感知模块技术路径已趋于收敛&#xff0c;自动驾驶从创造型行业迈向工程型行业。在特斯拉的引领下&#xff0c;国内主机厂2022年以来纷纷跟随特斯拉相继提出“重感知、轻地图”技术方案&#xff0c;全球自动驾驶行业感知模块技术路径从百花齐放开始走向收敛。我们认为主机厂智能…

波斯猫 6页面 宠物动物 长毛猫 HTML5 带背景音乐 JS图片轮播特效 滚动文字 鼠标经过图片 JS时间代码

波斯猫 6页面 宠物动物 长毛猫 HTML5 带背景音乐 JS图片轮播特效 滚动文字 鼠标经过图片 JS时间代码 注册表单 宠物网页成品 海量学生网页成品 个人博客 人物明星 城市家乡 旅游景点 美食特产 购物电商 公司企业 学校大学 科普教育 宠物动物 鲜花花卉 植物水果 茶叶咖啡 健康生…

目标识别项目:基于Yolov7-LPRNet的动态车牌目标识别算法模型(一)

前言 目标识别如今以及迭代了这么多年&#xff0c;普遍受大家认可和欢迎的目标识别框架就是YOLO了。按照官方描述&#xff0c;YOLOv8 是一个 SOTA 模型&#xff0c;它建立在以前 YOLO 版本的成功基础上&#xff0c;并引入了新的功能和改进&#xff0c;以进一步提升性能和灵活性…

【springboot】乡镇卫生院、二甲医院云HIS运维平台源码

目录 云HIS运营管理 ​编辑电子病历主模块&#xff1a;包括门诊电子病历、住院电子病历等子模块 &#xff08;1&#xff09;门诊电子病历功能简介 &#xff08;2&#xff09;住院电子病历功能简介 ▶患者列表主模块&#xff1a;包括患者信息子模块 &#xff08;1&#xf…

【应用多元统计分析】--多元数据的直观表示(R语言作图)

例1.2 为了研究全国31个省、市、自治区2018年城镇居民生活消费的分布规律&#xff0c;根据调查资料做区域消费类型划分。 指标&#xff1a; 食品x1&#xff1a;人均食品支出(元/人) 衣着x2&#xff1a;人均衣着商品支出(元/人) 居住x3&#xff1a;人均居住支出(元/人) 生活x4…

基于ARIMA+SARIMA的航空公司 RPM 时间序列预测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

快速幂模板

#include<bits/stdc.h> using namespace std;typedef long long ll;ll n; ll Mi[40];ll quick_M(ll a, ll b, ll p) {// 初始化答案为1ll res 1;// 将b用二进制表示while(b){// 如果二进制位为1&#xff0c;则相乘&#xff08;如上图右半边&#xff09;if(b & 1) re…

STM32(6)中断

1.中断 1.1 中断的概念 STM32的中断&#xff1a; 1.2 中断优先级 用数字的大小表示中断优先级的高低&#xff0c;数字的范围&#xff1a;0000--1111&#xff08;二进制&#xff09;&#xff0c;即0-15&#xff0c;共16级优先级。 进一步对这4位二进制数进行划分&#xff0c;可…

芯片ERP:应用广泛的领域及其影响

在现代科技快速发展的时代&#xff0c;芯片ERP(企业资源规划)已成为许多行业不可或缺的工具。这种集成了先进技术和先进管理理念的系统&#xff0c;极大地提高了企业的运营效率和竞争力。那么&#xff0c;芯片ERP主要应用在哪些领域呢?本文将为您一一揭晓。 一、电子制造行业 …

STM32(11)按键产生中断

1.初始化IO引脚&#xff0c;设置模式&#xff0c;速度等 2.设置AFIO&#xff08;配置EXTI的引脚映射&#xff09;&#xff0c;记得开启时钟 3.配置EXTI的通道&#xff08;EXTI0和EXTI1&#xff09; 4.配置NVIC 4.1 中断优先级分组 4.2 配置中断 5.编写中断响应函数 在中断向量…

《一》在Vue中搭建Three.js环境(超详细、保姆级),创建场景、相机、渲染器

目录 Three.js简介创建vue项目引入Three.js实际操作环节文件目录创建初始化场景、相机 Three.js简介 Three.js 是一款基于 WebGL的 JavaScript 3D 库&#xff0c;它封装了 WebGL API&#xff0c;为开发者提供了简单易用的 API 来在 Web 浏览器中展示 3D 图形。Three.js 提供了…

uniapp问卷调查(单选)

前言 该代码片段只支持问卷调查的单选功能 使用组件库 配置 | uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架 (uviewui.com) 代码 <template> <view> <view v-for"(item, index) in radiolist1" :key"index"> …

6 款顶级的 iPhone 数据恢复软件解决方案值得您花时间!

尽管iOS为您的数据提供了很多安全网&#xff08;例如iCloud&#xff09;&#xff0c;但由于事故、病毒等原因&#xff0c;仍然可能会发生“不可逆转”的数据丢失。在这种情况下&#xff0c;最好的DIY解决方案是使用iPhone数据恢复软件&#xff0c;这是一种利用先进算法直接从设…

中国电子学会2020年12月份青少年软件编程Sc ratch图形化等级考试试卷四级真题

【 单选题 】 1.陶朱家开了一间小卖部&#xff0c;学了编程的他想编写一个程序帮助分析小卖部各种商品的售卖情况。如下图所示&#xff0c;目前各个商品的名称和销售量分别存在了两张列表里&#xff0c;一一对应&#xff0c;并且每一样商品的销售量都不同。陶朱要先找出销售量…

selenuim【1】($x(‘xpath语法’)、WebDriverWait())

文章目录 初学selenuim记录1、执行driver webdriver.Chrome()后很久才打开浏览器2、浏览器多元素定位 $x(‘xpath语法’)3、打开浏览器driver.get("网址")执行了很久才开始定位元素&#xff1a;等待&#xff08;1&#xff09;driver.set_page_load_timeout(t)&#…

在Python中使用多线程(通俗版本)

一、多线程的介绍&#xff1a; 1.进程 通常一个进程包含一个或者多个线程&#xff0c;每个进程有自己独立的一块内存空间&#xff0c;所有的线程共享这一块空间&#xff0c;例如&#xff1a;在Windows操作系统中&#xff0c;一个运行的xx.exe就是一个进程。 2.线程 一个进程…

低代码流程引擎实战:让表单字段成为流程节点审批人的得力助手!

在现代企业的日常运营中&#xff0c;流程审批是保障工作高效、规范进行的关键环节。随着企业对于灵活性和高效性的需求不断增长&#xff0c;传统的固定审批人设置已无法满足多变的业务场景。在JVS低代码中“设置流程节点审批人为表单字段”这一功能&#xff0c;旨在通过动态配置…