代码随想录第43天|1049.最后一块石头的重量II 494. 目标和

news/2024/11/29 19:40:59/

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

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

代码随想录 (programmercarl.com)

动态规划之背包问题,这个背包最多能装多少?LeetCode:1049.最后一块石头的重量II_哔哩哔哩_bilibili

有一堆石头,用整数数组 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],这就是最优值。示例 2:
输入:stones = [31,26,33,21,40]
输出:5提示:
  • 1 <= stones.length <= 30
  • 1 <= stones[i] <= 100

把石头尽量分成数值相等的两堆,相减的值才会最小。

本题物品的重量为stones[i],物品的价值也为stones[i]。

动规五部曲:

1、确定dp数组以及下标的含义:dp[j] 表示容量为j的背包,可以背的最大重量为dp[j];

2、确定递推公式:dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);

3、dp数组如何初始化:初始化一个长度为target+1的整形dp,用来存储动态规划中的结果:

 int[] dp = new int[target + 1];

4、确定遍历顺序:物品遍历的for循环在外,循环背包的for循环在内:

for (int i = 0; i < stones.length; i++) {// 内层循环从 target 开始,递减到 stones[i],采用倒序的方式。for (int j = target; j >= stones[i]; j--) {// 动态规划的状态转移方程,计算两种情况下的最大值:放入当前石头和不放入当前石头。dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);}}

5、举例推导dp数组:

输入[2,4,1,1], 此时target=4:

综合代码:

class Solution {// 定义一个公共方法,名称为 lastStoneWeightII,接受一个整型数组 stones,并返回一个整数。public int lastStoneWeightII(int[] stones) {// 初始化一个变量 sum,用于存储 stones 数组中所有元素的总和。int sum = 0;// 遍历 stones 数组,将所有元素的值累加到 sum 中。for (int i : stones) {sum += i;}// 将 sum 的值除以 2,并将结果赋给变量 target。int target = sum >> 1;// 初始化一个长度为 target + 1 的整型数组 dp,用于存储动态规划中的结果。int[] dp = new int[target + 1];// 使用两层循环来进行动态规划计算。for (int i = 0; i < stones.length; i++) {// 内层循环从 target 开始,递减到 stones[i],采用倒序的方式。for (int j = target; j >= stones[i]; j--) {// 动态规划的状态转移方程,计算两种情况下的最大值:放入当前石头和不放入当前石头。dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);}}// 返回 stones 中所有元素的总和减去 2 倍的 dp[target]。return sum - 2 * dp[target];}
}

 494. 目标和

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

代码随想录 (programmercarl.com)

动态规划之背包问题,装满背包有多少种方法?| LeetCode:494.目标和_哔哩哔哩_bilibili

有一堆石头,用整数数组 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],这就是最优值。

示例 2:

输入:stones = [31,26,33,21,40]
输出:5

提示:

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

 假设加法对应的总共和为x,那么减法对应的总和就是sum-x; 所以 x-(sum-x)=target;

x=(sum+target)/2; 此时就转化为:装满容量为x的背包,有几种方法。

之前遇到的都是01背包问题,在01背包问题中,物品都只能使用一次;而本题是装满有几种方法,是组合问题。

动规五部曲

1、确定dp数组以及下标的含义:dp[j] 表示:填满j这么大容量的包,有dp[j]种方法;

2、确定递推公式:

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

3、dp数组如何初始化:dp[0]=1;

4、确定遍历顺序:nums外循环,target内循环;

5、举例推导dp数组:

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

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

dp数组状态变化如下:

综合代码:

class Solution {// 定义一个公共方法,名称为 findTargetSumWays,接受一个整型数组 nums 和一个整数 target,并返回一个整数。public int findTargetSumWays(int[] nums, int target) {// 初始化一个变量 sum,用于存储 nums 数组中所有元素的总和。int sum = 0;for (int i = 0; i < nums.length; i++) sum += nums[i];// 如果 target 的绝对值大于 sum,那么是没有方案的,直接返回 0。if (Math.abs(target) > sum) return 0;// 如果 (target + sum) 除以 2 的余数不为 0,也是没有方案的,直接返回 0。if ((target + sum) % 2 == 1) return 0;// 计算背包的大小,即 (target + sum) 除以 2,这是动态规划的一个关键参数。int bagSize = (target + sum) / 2;// 初始化一个长度为 bagSize + 1 的整型数组 dp,用于存储动态规划中的结果。int[] dp = new int[bagSize + 1];// 初始时,背包容量为 0 的情况有一种方案,因此 dp[0] 初始化为 1。dp[0] = 1;// 使用两层循环进行动态规划计算。for (int i = 0; i < nums.length; i++) {// 内层循环从 bagSize 开始递减到 nums[i],采用倒序的方式。for (int j = bagSize; j >= nums[i]; j--) {// 动态规划的状态转移方程,计算两种情况下的方案数:放入当前元素和不放入当前元素。dp[j] += dp[j - nums[i]];}}// 返回背包容量为 bagSize 时的方案数。return dp[bagSize];}
}

 

 


http://www.ppmy.cn/news/1431282.html

相关文章

南京邮电大学数学实验A 作业5 函数与方程 答案 | 《MATLAB数学实验》第三版 第四章 课后习题答案

若要获得更好的阅读体验&#xff0c;请前往 链接。 求点赞 求点赞 求点赞。 1(课本习题1) 求下列多项式的所有根&#xff0c;并验算&#xff1a; (1) x 2 x 1 x^{2} x 1 x2x1; (2) 3 x 5 − 4 x 3 2 x − 1 3x^{5} - 4x^{3} 2x - 1 3x5−4x32x−1; (3) 5 x 23 −…

深入解析操作系统

1. 前言 本文旨在全面解析操作系统的概念、功能、类型以及其在现代计算机系统中的重要性。通过深入剖析操作系统的资源管理、进程管理、内存管理、文件管理和设备管理等核心功能&#xff0c;并结合实际案例&#xff0c;展现操作系统如何优化计算机性能、提高用户体验并促进多任…

【JavaSE启航篇 02】Java的诞生:从默默无名的Oak到全球化的Java

文章目录 【JavaSE那些年专栏 02】Java语言的诞生&#xff1a;Oak的创始、JDK版本迭代与Java的全球化01 Java 发展历史1.1 Java的诞生与早期发展1.2 Java技术的推广与普及1.3 Java技术的里程碑版本1.4 企业级J2EE崛起1.5 JDK与JVM迭代优化1.6 Java的商业化与Oracle的收购1.7 Ja…

Ubuntu-18.04本地化部署Rustdesk服务器

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、配置防火墙二、安装三大件1.下载三大件2.安装三大件 三、安装客户端1.下载客户端1.Windows2.Linux 四、配置客户端连接服务器五、总结 前言 如果你是想数据…

00_Qt概述以及如何创建一个QT新项目

Qt概述 1.Qt概述1.1 什么是Qt1.2 Qt的发展史1.3 支持的平台1.4 Qt版本1.5 Qt的下载与安装1.6 Qt的优点 2.QT新项目创建3.pro文件4.主函数5.代码命名规范和快捷键 1.Qt概述 1.1 什么是Qt Qt是一个跨平台的C图形用户界面应用程序框架。它为应用程序开发者提供建立艺术级图形界面…

【Linux系统化学习】线程互斥 | 互斥量(锁)

目录 多线程抢票问题 对问题的解释 代码的原子性 线程互斥 上述问题的解决方法 相关概念 互斥量&#xff08;锁&#xff09; 锁的定义和初始化 锁的销毁 加锁和解锁 加锁注意事项 使用锁注意事项 锁的原理 可重入与线程安全 概念 常见线程不安全的情况 常见线…

Vs Code npm install 报错解决方法

用的人家的前端框架发现是封装过的&#xff0c;要修改人家前端的话还得把前端源码放在Vs Code 上运行&#xff0c;后端放在IDEA上运行&#xff0c;然后前后端并行开发&#xff0c;在配置前端环境时遇到&#xff1a; npm install 这个的原因是我把node下载到D盘了权限不够框框爆…

Redis入门到通关之Redis数据结构-Hash篇

文章目录 ☃️ 概述☃️底层实现☃️源码☃️其他 欢迎来到 请回答1024 的博客 &#x1f353;&#x1f353;&#x1f353;欢迎来到 请回答1024的博客 关于博主&#xff1a; 我是 请回答1024&#xff0c;一个追求数学与计算的边界、时间与空间的平衡&#xff0c;0与1的延伸的后…