DP(4) | 0-1背包 | Java | LeetCode 1049, 494, 474 做题总结

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

和 LC 416.分割等和子集 类似

  • 思路(我没有思路):
    两块石头相撞,这里没有想到的一个点是,相撞的两个石头要几乎相似
    以示例1为例,stones = [2,7,4,1,8,1],如果从左到右相撞,得到的不是最优结果
    最优结果是相撞后重量最小的

    stones = [2,7,4,1,8,1],总和23,一半为11,把这组石头分为一组11 一组12,他们相撞就是1

    0-1背包,M个物品放入容量为N的背包中,物品价值value、重量weight

递归五步:

  1. 确定dp数组(dp table)以及下标的含义
    背包重量 j 最大价值 dp[j] 最大重量 dp[j]
  2. 确定递推公式
    价值: dp[j] = Math.max(dp[j], dp[j-weight[i]] +value[i])
    重量:dp[j] = Math.max(dp[j], dp[j-stones[i]] +stones[i])
  3. dp数组如何初始化
    dp[0] = 0,其余也都是0
    ② 由于题目定义 1 <= stones.length <= 30; 1 <= stones[i] <= 100 所以极端情况下每个元素都为100,共30个元素,sum = 3000 , half = 1500
    int[]dp = new int [1501]
  4. 确定遍历顺序
    for物品 { for背包 }
  5. 举例推导dp数组
    求得一组石头的重量是 a = dp[target] ,另一组为 b= sum-dp[target]
    这里 b-a一定大于零,因为sum/2是向下取整的
  • ac-二维数组版本
    写的时候出错:① 递推公式写错 ② 初始化行列不分 ③ 初始化的值应为固定的value[0]
    这道题目的二维数据版本空间内存消耗很多。
class Solution {public int lastStoneWeightII(int[] stones) {int sum = 0;for(int i=0; i<stones.length; i++) {sum += stones[i];}int bagSize = sum/2; // N// M = stones.lengthint[][] dp = new int[stones.length][bagSize+1]; //二维数组空间多很多//初始化第0行,物品0从哪里开始放for(int i=stones[0]; i<bagSize+1; i++) { // weight[0]dp[0][i] = stones[0];//value[0]错了}for(int i=1; i<stones.length; i++) {for(int j=1; j<bagSize+1; j++) {if(j<stones[i]) {dp[i][j] = dp[i-1][j];} else {dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-stones[i]] + stones[i] );}}}return sum-2*dp[stones.length-1][bagSize];}
}

在这里插入图片描述

  • ac-滚动数组版本
    写的过程中:递推公式又错了。
class Solution {public int lastStoneWeightII(int[] stones) {int sum = 0;for(int i=0; i<stones.length; i++) {sum += stones[i];}int bagSize = sum/2; // Nint M = stones.length; // Mint[] dp = new int[bagSize+1];for(int i=0; i<M; i++) {for(int j=bagSize; j>=stones[i]; j--) { // weight[i]//两种情况,要么放,要么不放dp[j] = Math.max(dp[j],dp[j-stones[i]]+stones[i]); // 1 weight 2 value}}return sum-2*dp[bagSize];}
}

494. 目标和

思路

准备两个背包,一个背包package_a存放标记为正的元素,另一个背包package_b存放标记为负的元素。package_a - package_b = target

设nums的元素和为sum, 可以列出方程:

package_a - package_b = target;
package_a + package_b = sum;

所以 package_a = (target + sum)/2。 所以根据题意给的target和sum,我们可以求出package_a的值。

那这道题就可以转化为:给定一个大小为package_a的背包,有多少种组合方式能把背包装满? 妥妥的0-1背包。

元素放或者不放

答案

class Solution {public int findTargetSumWays(int[] nums, int target) {int sum = 0;for(int i=0; i<nums.length; i++) {sum += nums[i];}        if(sum < Math.abs(target)){return 0;}if((sum + target) % 2 != 0) {return 0;}int bagSize = (target+sum)/2;int M = nums.length;int[][]dp = new int[M][bagSize+1];//首行-初始化if(nums[0] <= bagSize) {dp[0][nums[0]] = 1;}//首列-初始化int zeroNum = 0;for(int i=0; i<M; i++) {if(nums[i] == 0) {zeroNum++;}dp[i][0] = (int) Math.pow(2,zeroNum);// 有0的话,选或不选 2的x次方// 没有0,首列全部设为1??什么意思}for(int i=1; i<M; i++) {for(int j=1; j<bagSize+1; j++) {if(nums[i]>j) {dp[i][j] = dp[i-1][j];} else {dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]];}}}return dp[M-1][bagSize];}
}

难点

(1)错误状况 return 0的情况

  //如果target的绝对值大于sum,那么是没有方案的if (Math.abs(target) > sum) return 0;//如果(target+sum)除以2的余数不为0,也是没有方案的if ((target + sum) % 2 == 1) return 0;

(2)递推公式 dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]]的由来

在这里插入图片描述
(3)数组的初始化

  • 首行初始化:只初始化二维数组M*N里的一个格子,就是 j=nums[0] 时,也就是 只选 物品0,其余都不选,此时情况赋为1。
  if(nums[0] <= bagSize) {dp[0][nums[0]] = 1;}
  • 首列初始化:
    (1)数组元素有0的话,选或不选 2的x次方
    (2)数组元素没有0,首列全部设为1??什么意思
    dp[i][0] = 1,背包容量为0的时候,情况为1,或许可以理解为 这题本来就不是放背包,是求和??
    看到别人的解释:任何一个物品,只要选择不取的方案,就能凑成0容量的背包
	int zeroNum = 0;for(int i=0; i<M; i++) {if(nums[i] == 0) {zeroNum++;}dp[i][0] = (int) Math.pow(2,zeroNum);// (1)数组元素有0的话,选或不选 2的x次方// (2)数组元素没有0,首列全部设为1??什么意思// dp[i][0] = 1,背包容量为}

出错点

① Math.pow(); 之前要写 (int) 强制类型转换

Line 32: error: incompatible types: possible lossy conversion from double to intdp[i][0] = Math.pow(2,zeroNum);

打印dp(为了方便理解)

(1)

  int[]nums = {1,1,1,1,1};int target = 3;
  • 初始化

在这里插入图片描述

  • 最终dp

在这里插入图片描述

(2)打印

  int[]nums = {0,1,0,1,1};int target = 1;
  • 初始化

在这里插入图片描述

  • 最终dp

在这里插入图片描述

474.一和零

我的思路

这道题放在代码随想录的0-1背包分类下,怎么抽象为背包问题?
重量满足两个维度 m n,同时尽可能是最大长度,三维背包?
int dp[strs.length][m+1][n+1]
dp[k][i][j]:0-k物品(strs[])中任选,拥有最大的子集长度(i表示0长度,j表示1长度)1. 递推公式(假设和0-1推导方法相同)
(1)【不取】假设取物品k,但超过了容量(i,j)的限制,所以不放k
if(strs[k]0 1数量 > m n) 这里任意一个大于都不可以
dp[k][i][j] = dp[k-1][i][j]  
(2)【取】
A. 能放但是不放  dp[k][i][j] = dp[k-1][i][j]  
B. 能放且放了    dp[k][i][j] = dp[k-1][i-weight0[k]][j-weight1[k]]+value[k]weight0[k]是字符串k拥有的0的长度 ,weight1[k]是字符串k拥有的1的长度,value[k]是字符串k的长度
总和 dp[k][i][j] = Math.max(dp[k-1][i][j] , dp[k-1][i-weight0[k]][j-weight1[k]]+value[k])2. 初始化dp数组
三维数组抽象为一个立方体
(1) dp[0][i][j] 相当于顶面,这一面表示物品0,放进容量为(i,j)的背包里,拥有的最大子集长度 
for(int t1=weight0[0]; t1<m+1; t1++ ) {for(int t2=weight1[0]; t2<n+1; t2++) {dp[0][i][j] = value[0]}
}(2) dp[k][0][j] 首面,这一面表示物品k,放进容量为(0,j)的背包里,拥有的最大子集的长度,
for(int a=0; a<strs.length; a++ ) {for(int t=0; t<n+1; t++) {if(weight1[a] <= t) {dp[a][0][t] = value[a]}}
}(3)dp[k][i][0]左面,这一面表示物品k,放进容量为(i,0)的背包里,拥有的最大子集的长度,
for(int a=0; a<strs.length; a++ ) {for(int t=0; t<m+1; t++) {if(weight0[a] <= t) {dp[a][t][0] = value[a]}}
}3.遍历顺序
for(int a=0; a<strs.length; a++) {for(int t1=0; t1<m+1; t1++) {for(int t2=0; t2<n+1; t2++) {dp[a][t1][t2] = }} 
}
  • 我的想法错误点:value表示的子集的多少,不是字符的长度。初始化想的很复杂

正确版本

class Solution {public int findMaxForm(String[] strs, int m, int n) {int len = strs.length;int[][][]dp = new int [len + 1][m + 1][n + 1];for(int i=1; i<len+1; i++) {int[]zeroOnes = getZeroOne(strs[i - 1]);int zero=zeroOnes[0], one=zeroOnes[1];for(int j=0; j<m+1; j++) {for(int k=0; k<n+1; k++) {dp[i][j][k] = dp[i - 1][j][k];if(zero <= j && one <= k) {dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i - 1][j - zero][k - one]+1);}}}}return dp[len][m][n];}public int[] getZeroOne(String s) {int[] num = new int[2];for(int i=0; i<s.length(); i++) {if(s.charAt(i) == '0') {num[0]++;} else {num[1]++;}}return num;}
}

错误点

这数组初始化在哪?
为什么for j=0 k=0从0开始?

java

  • 除以 2 :int target = sum >> 1;

  • 强制类型转换:int x = (int)Math.pow(a, b); 意思是 a的b次方
    public static double pow(double 基数,double 幂次)

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

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

相关文章

基于电鸿(电力鸿蒙)的边缘计算网关,支持定制

1 产品信息 边缘计算网关基于平头哥 TH1520 芯片&#xff0c;支持 OpenHarmony 小型系统&#xff0c;是 连接物联网设备和云平台的重要枢纽&#xff0c;可应用于城市基础设施&#xff0c;智能工厂&#xff0c;智能建筑&#xff0c;营业网点&#xff0c;运营 服务中心相关场…

synergy配置

今天介绍一个电脑同步软件synergy。 我们开发时一般会用两套设备&#xff0c;如果使用两套键盘操作起来会很麻烦&#xff0c;这个软件就是解决这个问题&#xff0c;可以使用一套键盘同时操作两台电脑&#xff0c;另一台作为客户端被控制。 安装 在两台电脑上各自下载安装syne…

使用IDEA编写lua脚本并运行

下载lua https://github.com/rjpcomputing/luaforwindows/releases 是否创建桌面快捷方式&#xff1a;我们的目标是使用IDEA编写lua脚本&#xff0c;所以不需要勾选。后面需要的话&#xff0c;可以到安装目录下手动创建快捷方式 环境变量自动配置 安装后会自动配置好环境变量…

轻量级文本编辑器 | Notepad-- v2.17 官方版

软件简介 Notepad--是一款国产的跨平台轻量级文本编辑器&#xff0c;旨在作为 Notepad 的替代品。它使用 C 编写&#xff0c;支持 Windows、Mac、Linux 等多种操作系统。 鉴于某些Notepad竞品作者的不当言论&#xff0c;Notepad--的意义在于&#xff1a;减少一点错误言论&…

持续集成08--Jenkins邮箱发送构建信息及测试报告

前言 在持续集成&#xff08;CI&#xff09;和持续部署&#xff08;CD&#xff09;的自动化流程中&#xff0c;及时通知团队成员关于构建的成功或失败是至关重要的。Jenkins&#xff0c;作为强大的CI/CD工具&#xff0c;提供了多种通知机制&#xff0c;其中邮件通知是最常用且有…

拖拽上传(预览图片)

需求 点击上传图片&#xff0c;或直接拖拽图片到红色方框里面也可上传图片&#xff0c;上传后预览图片 效果 实现 <!DOCTYPE html> <html lang"zh-cn"><head><meta charset"UTF-8"><meta name"viewport" content&…

Unity动画系统(4)

6.3 动画系统高级1-1_哔哩哔哩_bilibili p333- 声音组件添加 using System.Collections; using System.Collections.Generic; using UnityEngine; public class RobotAnimationController : MonoBehaviour { [Header("平滑过渡时间")] [Range(0,3)] publ…

爬虫瑞数5案例:某大学总医院

声明: 该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关 一、瑞数简介 瑞数动态安全 Botgate(机器人防火墙)以“动态安全”技术为核心,通过动态封装、动态验证、动态混淆、动态令牌等技术对服务器网页底层代码持续动态变换,…

LLM(大语言模型)解码时是怎么生成文本的?

Part1配置及参数 transformers4.28.1 源码地址&#xff1a;transformers/configuration_utils.py at v4.28.1 huggingface/transformers (github.com) 文档地址&#xff1a;Generation (huggingface.co) 对于生成任务而言&#xff1a;text-decoder, text-to-text, speech-…

vue使用x6画流程图,简单使用

官网 https://x6.antv.antgroup.com/tutorial/getting-started 安装 npm install antv/x6 --save 使用 <template><div>3333<div id"container" style"width: 800px;height: 800px;"></div></div> </template> <…

网络安全----防御----防火墙双机热备

实验要求&#xff1a; 1&#xff0c;对现有网络进行改造升级&#xff0c;将当个防火墙组网改成双机热备的组网形式&#xff0c;做负载分担模式&#xff0c;游客区和DMZ区走FW4&#xff0c;生产区和办公区的流量走FW1 2&#xff0c;办公区上网用户限制流量不超过100M&#xff0…

WPF/C#:实现导航功能

前言 在WPF中使用导航功能可以使用Frame控件&#xff0c;这是比较基础的一种方法。前几天分享了wpfui中NavigationView的基本用法&#xff0c;但是如果真正在项目中使用起来&#xff0c;基础的用法是无法满足的。今天通过wpfui中的mvvm例子来说明在wpfui中如何通过依赖注入与M…

第三篇 Vue项目目录结构介绍

1、最外层目录结构 passagerFrontPage ├── .vscode //vscode配置&#xff0c;不用理会 ├── node_modules //项目依赖&#xff0c;npm install命令执行后自动生成 ├── public //公共资源存放 ├── src //源码 ├── tests //选装&#xff1a;测试模块 ├── .git…

最新开源的PDF版面分析工具 PDF-Extract-Kit

最近有一个新开源的版面分析的模型&#xff0c;做PDF版面分析效果非常好。而且对公式的解析效果比较好。虽然现在star数量不高&#xff0c;但是绝对会涨起来的。我们调研对比过很多开源的工具&#xff0c;效果都强差人意&#xff0c;这个是我看到的最满意的一个。甚至要比我们生…

使用 XPath 定位 HTML 中的 img 标签

引言 随着互联网内容的日益丰富&#xff0c;网页数据的自动化处理变得愈发重要。图片作为网页中的重要组成部分&#xff0c;其获取和处理在许多应用场景中都显得至关重要。例如&#xff0c;在社交媒体分析、内容聚合平台、数据抓取工具等领域&#xff0c;图片的自动下载和处理…

Springboot 启动时Bean的创建与注入-面试热点-springboot源码解读-xunznux

Springboot 启动时Bean的创建与注入&#xff0c;以及对应的源码解读 文章目录 Springboot 启动时Bean的创建与注入&#xff0c;以及对应的源码解读构建Web项目流程图&#xff1a;堆栈信息&#xff1a;堆栈信息简介堆栈信息源码详解1、main:10, DemoApplication (com.xun.demo)2…

【开发踩坑】使用PageHelper工具正常sql后面多无关语句

背景 SQL日志打印出现了脏东西&#xff1a; 本来结束的 where muc.code ?;后面凭空多出了一个 LIMIT语句 ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your …

2024辽宁省数学建模B题【钢铁产品质量优化】原创论文分享

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2024 年辽宁省大学数学建模竞赛B题钢铁产品质量优化完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文。 B题论文…

解决element-ui e-table表格中使用多选,当翻页时已选中的数据丢失

用element-ui中的table时&#xff0c;当有多选又有翻页功能时&#xff0c;点击翻页后之前选中的数据会丢失&#xff0c;怎么使表格具有记忆功能呢 element-ui API中有几个属性可以供我们完美解决这个问题 1.单元格的属性和方法&#xff1a; 2.表格的方法&#xff1a; <el-…

Linux部署Prometheus+Grafana

【Linux】PrometheusGrafana 一、Prometheus&#xff08;普罗米修斯&#xff09;1、Prometheus简述2、Prometheus特点3、Prometheus生态组件4、Prometheus工作原理 二、部署Prometheus1、系统架构2、部署Prometheus3、修改配置文件4、配置系统启动文件 三、部署 Node Exporter …