力扣爆刷第127天之动态规划五连刷(整数拆分、一和零、背包)

devtools/2024/9/23 10:20:02/

力扣爆刷第127天之动态规划五连刷(整数拆分、一和零、背包)

文章目录

      • 力扣爆刷第127天之动态规划五连刷(整数拆分、一和零、背包)
      • 关于0 1 背包问题的总结
          • 01背包遍历顺序:
          • 完全背包遍历顺序:
      • 一、343. 整数拆分
      • 二、96. 不同的二叉搜索树
      • 三、416. 分割等和子集
      • 四、1049. 最后一块石头的重量 II
      • 五、494. 目标和

关于0 1 背包问题的总结

背包问题:一维数组,dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i])。

01背包遍历顺序:

先物品后背包,物品正序,背包逆序。

如若背包正序则会出现同一个物品重复放入,如物品1重量为1,背包空间为1时放入了,背包空间为2时又放入了。
如果先背包后物品,为了避免重复放入背包依然是逆序,背包容量固定时,每种背包容量只能放入一个物品,即为最大的物品,小的物品都放不进来或者被覆盖了。

求组合数排列数:dp[j] += dp[j - nums[i]]

完全背包遍历顺序:

物品背包没有先后顺序,物品背包都是正序。因为同一个物品不限量可以放入多次,在背包采用正序中。

完全背包求组合数,物品在外,背包在内。求排列数,背包在外,物品在内。

一、343. 整数拆分

题目链接:https://leetcode.cn/problems/integer-break/description/
思路:整数拆分是把整数拆分成k个数使其乘积最大,最低是拆分成两个数,根据题目要求的目标定义dp[i]表示i被拆分后相乘的最大值,对于任意一个数来说,最低是拆分成两个数,然后就是两个数以上,我们要求的就是这些情况中的最大值,显然发现是有状态转移的关系的,如dp[i],如果拆分成两个数,那就是(i-j)* j,如果拆分成两个数以上就是dp[i-j] * j,每一个数都要遍历这些情况,故 dp[i] = Math.max(Math.max(dp[i-j] * j, (i-j)*j), dp[i]);

class Solution {public int integerBreak(int n) {int[] dp = new int[n+1];dp[2] = 1;for(int i = 3; i <= n; i++) {for(int j = 1; j <= i/2; j++) {dp[i] = Math.max(Math.max(dp[i-j] * j, (i-j)*j), dp[i]);} } return dp[n];}
}

二、96. 不同的二叉搜索树

题目链接:https://leetcode.cn/problems/unique-binary-search-trees/
思路:做动态规划的题目主要是找出重叠子问题,推导出状态转移方程,定义dp[i]表示i个节点的二叉搜索树有多少种结构类型,dp[3]也就是有3个节点我们可以看出,1为根节点有两种,2为根节点有1种,3为根节点有2种,但1为根节点时,右子树有两个节点,这2个节点的种类数量其实是和dp[2]是一样的,由此我们是可以看出关系来的,有N个节点的二叉搜索树的类型数量就等于1-N每一个数字作为根节点时种类数量的累加,这里正好有重叠子问题。故递推公式为dp[i] += dp[j-1] * dp[i-j];
以dp[3]推导举例:
1为根节点,dp[0]*dp[2]。
2为根节点,dp[1]*dp[1]。
3为根节点,dp[2]*dp[0]。这里是有复用关系的。
在这里插入图片描述

class Solution {public int numTrees(int n) {int[] dp = new int[n+1];dp[0] = 1;for(int i = 1; i <= n; i++) {for(int j = 1; j <= i; j++) {dp[i] += dp[j-1] * dp[i-j];}}return dp[n];}
}

三、416. 分割等和子集

题目链接:https://leetcode.cn/problems/partition-equal-subset-sum/description/
思路:0 1背包问题,划分等和子集,如果和为偶数就可以划分,奇数就不能划分。偶数可以划分,就等于用数组里的数把总和的一半给填满,那么就可以划分等和子集,从而转化为0 1 背包问题。
0 1 背包特点,物品在外,背包在内,背包逆序。内外关系为的是防止,大物品放入后,小物品无法再放入。背包逆序为的是防止物品重复放入。

class Solution {public boolean canPartition(int[] nums) {int sum = 0;for(int i = 0; i < nums.length; i++) {sum += nums[i];}if(sum % 2 == 1) return false;sum /= 2;int[] dp = new int[sum+1];for(int i = 0; i < nums.length; i++) {for(int j = sum; j >= nums[i]; j--) {dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i]);}}return dp[sum] == sum;}
}

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

题目链接:https://leetcode.cn/problems/last-stone-weight-ii/description/
思路:求最后一块是否的重量,就是两两抵消,求最后剩余的无法抵消的数,转换思路想一想其实就是尽量把石头分成两堆大小接近的堆,然后比较最小差值,所以题目就转变成了0 1背包问题,总数和的一半作为背包,求的结果后,乘2与总数相减即得最后一块是否的重量。

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

五、494. 目标和

题目链接:https://leetcode.cn/problems/target-sum/description/
思路:0 1 背包求组合数,想办法转化为背包,得到背包空间,因为分为正数和负数,a + b = sum; a - b = target。
a = (sum+target) / 2;
由此可以得到正数背包,从而转变从背包求组合数,定义dp[j]表示,背包空间为j时的物品组合数,那么自然,递推公式为dp[j] += dp[j - nums[i]]; 所以需要初始化为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) || (sum + target) % 2 == 1) return 0;int left = Math.abs((sum + target) / 2);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];}
}

http://www.ppmy.cn/devtools/16852.html

相关文章

vue2实现字节流byte[]数组的图片预览

项目使用vantui框架&#xff0c;后端返回图片的字节流byte[]数组&#xff0c;在移动端实现预览&#xff0c;实现代码如下&#xff1a; <template><!-- 附件预览 --><div class"file-preview-wrap"><van-overlay :show"show"><…

js网络请求---fetch和XMLHttpRequest的用法

fetch 语法规则 let promise fetch(url, [options]) //url —— 字符串&#xff1a;要访问的 URL。 //options —— 对象&#xff1a;可选参数&#xff1a;method&#xff0c;header 等。 fetch函数返回一个promise&#xff0c;若存在网络问题&#xff0c;或网址不存在&…

先进制造aps专题四 计划型简单aps系统(plan)和排产型复杂aps系统(Scheduling)的区别

计划型算法很简单&#xff0c;只考虑产品和产线/车间&#xff0c;一个产线/车间对于一个产品&#xff0c;产线/车间24小时生产&#xff0c;没有休息时间段&#xff0c;java web类型的aps系统都是这种类型&#xff0c;这种其实是计划型的aps系统(plan) 要是排产考虑产品工序&am…

《架构风清扬-Java面试系列第27讲》Java中如何正确优雅关闭线程?

这道题也是容易答错的题目之一&#xff0c;原因是因为有一个stop方法容易误导大家 一般也是考核工作三年以内的小伙伴&#xff0c;不属于有难度的题目 但由于出现频率不低&#xff0c;所以&#xff0c;钊哥有必要跟小伙伴们聊一聊 来&#xff0c;老规矩&#xff0c;在往下看答案…

计算机视觉——两视图几何求解投影矩阵

上文我提到了通过图像匹配得到基本矩阵&#xff0c;接下来我们要接着求解投影矩阵。 计算投影矩阵思路 假设两个投影矩阵为规范化相机&#xff0c;因此采用基本矩阵进行恢复。在规范化相机下&#xff0c; P [ I ∣ 0 ] P[I|0] P[I∣0], P ′ [ M ∣ m ] P[M|m] P′[M∣m]。…

iOS 在OC旧项目中使用Swift进行混编

iOS 在OC旧项目中使用Swift进行混编 1、创建桥接文件 ​ 第一次在Swift创建OC文件&#xff0c;或者第一次OC创建Swift时&#xff0c;xcode会提示桥接&#xff0c;Creat Bridging Header即可,这个文件用于Swift调用OC文件&#xff0c;与OC调用Swift无关。 2、在TARGETS中设置D…

数字化革新:可视化墨水屏引领基板工艺MSAP贴膜阶段迈向无纸化高端制造应用背景

随着科技的飞速发展和环境保护意识的日益增强&#xff0c;制造印刷电路板&#xff08;PCB&#xff09;行业正面临着提升生产效率、降低资源消耗和推动绿色制造的迫切需求。 问题&#xff1a; PCB生产过程对洁净度要求高&#xff0c;传统打印的纸张会有粉尘&#xff0c;纸屑&am…

安卓原生项目工程结构说明

.gradle 和 .idea (自动生成) .gradle 是gradle下载好的缓存&#xff0c;如果有配置好的 下载好的缓存 直接会拿来用 没有会下载 生成 .idea 是编辑器的配置 app 代码主逻辑 目录 项目中的代码 资源都会在里面 工作的时候的核心目录 gradle 下载安卓的构建器gradle相关的配置信…