当前位置:网站首页>完全背包如何考虑排列问题
完全背包如何考虑排列问题
2022-06-22 18:43:00 【一枚小比特】
完全背包下的排列问题
题目来源:(力扣377)
https://leetcode.cn/problems/combination-sum-iv/
题干:
给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。
题目数据保证答案符合 32 位整数范围。
示例 1:
输入:nums = [1,2,3], target = 4
输出:7
解释:
所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
请注意,顺序不同的序列被视作不同的组合。
示例 2:
输入:nums = [9], target = 3
输出:0
常规的完全背包
说直白一点什么是完全背包:就是有一堆物品,每个物品有自己的价值和重量,现在手上有一个容重有上限的背包,让你去那一堆物品当中去挑着装,问怎么装能装出最大价值呢?如果每个物品只能用一次,那就是典型的0-1背包问题,而如果每个物品都能使用无数次,那就会转变为完全背包问题
0-1背包怎么处理?
通常维护一个二维数组dp [ i ] [ j ] :含义就是:前i个字符,在当前背包容量为j的情况下,所能得到的最大价值就是dp [ i ] [ j ]
那根据dp数组的定义,我们可以比较轻松的得到递推公式:
//1.如果当前背包装的下:
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-weight[i]+value[i]])//注意你要使用的i是下标还是就是1代表第一个物品,所以细节注意一下
//2.如果当前背包压根装不下,即j<weight[i]
dp[i][j] = dp[i-1][j]
而一般题目都会要求我们去返回一个dp [n] [target],n就是给了一个数组的长度,也就是说将整个数组都作为考虑的对象,target表示一个目的,比如能否等和的分割出一个子集啊那样的题,target就是所有元素的和除2得到,如果能在所给数组中挑选出某些个元素填满容量为target的背包,题目就可以返回true咯,很多题目都是0-1背包的抽象化.但是思路都差不多是这个.
但是0-1背包我认为最应该注意的地方:就是两层for循环遍历的顺序上,它有时候是先物品再背包,有时候只能反过来,有时候又都可以,那我发现:只有你预想的递推公式是依赖于[i-1]这样的前面的数据,那一般就都是先物品再背包,因为一行一行填二维数组时,你需要先拿到左上角的数据才能推出当前位置该填什么.就比如换零钱的问题,要用背包问题解决的话,背包的容量就是你想换的钱的金额,待选的物品就是那个数组,如果每个面额的钱只能有一次就是0-1背包,反之就是完全背包问题.然后填当前位置的时候,穷举出它所能依赖的前面你已经算出来的数据的所有情况,并依赖于它们给出你当前位置的值是多少,所以我认为对局部的穷举就是递推公式出来的关键,当然这只是个人总结啦,大家刷题可以试试这个思维,我怎么完全的考虑已经算出来的数据推出当前位置的数据是多少?就是这样
二维dp table可优化至一维
如果递推公式显示当前位置的数据只和它相邻的格格内的数据相关,那此时大概率是可以压缩的,怎么压缩呢?其实双层for循环的遍历顺序已经给了我们答案,比如先遍历i(行)再遍历j(列),也就是说你当前在填第i行的第j列的数据:dp[i] [j],如递推公式就拿上面的那个为例,其实你上一层外层的for循环给的第j列的数据和你当前i层遍历到的第j列数据都在同一层对吧,如果你讲i这个维度拍扁,你如果拿一个dp[j],啥都不干,其实你是拿到了二维数组中的dp[i-1] [j]的数据,所以:
dp[j] = Math.max(dp[j],dp[j-weight[i]+value[i]])
此时就会成功优化空间复杂度啦~
当然如果是什么倒着遍历,并且当前位置和已经算出来的三个位置的数据相关,可能还需要搭配一定的变量去记录某个数据,因为你不记录,就会被覆盖,那就再也拿不到了,比如你可以试试最长回文子序列的空间如何压缩,此处不再赘述
优化至一维有什么要注意的吗?
刚才也说到了,优化成一维的因为要拿老数据用,所以如果你内层for循环还是正序遍历的话,就会把老数据直接覆盖了,那你之后的位置还想拿老数据出来用,你就拿不到了,所以此时就需要将内层for循环变成倒叙遍历,正是因为二维数组一个位置填好了之后不会再被修改,所以你内层for循环即使是正序遍历也没事.
说那么多为什么?
因为本题如果仅仅是在0-1背包的基础之上考虑物品可被复用的话,就顶多上述提及的代码中将选择列表多加一个已选的物品即可完成物品复用.
但是不知道你注意过没用,如果先遍历物品再遍历背包,其实:我们假设物品有两个:1,2分别表示第一个和第二个物品的重量(也是价值)
那先遍历物品再遍历背包的话:每个背包里就一定是先1后2,而不会出现先2后1的情况,这就说明了:
先物品后背包的遍历顺序将给我们带来组合的结果
反过来呢?
先背包再物品,比如我们考虑一个包装满有几种方案可以吧,就设容量是3,有物品1,2
那这个包装满的方案就会包含1,2和2,1,虽然物品还是这两个物品,但却算作了两个不同的结果,所以:
先背包再物品的遍历顺序讲给我们带来排列的结果
那回到这个题,该怎么写呢?因为经过上述分析,我们知道本题在求排列,并且背包容量是target,并且呢还是一个完全背包问题.
如果我们定义dp[i] [j]是前i个数组元素,能有最多dp[i] [j]中方案组成j
那:
//递推公式就是:dp[i][j] = dp[i-1][j] + dp[i][j-1]
但是这样真的对吗?答案是否定的.
此时我们应当这样去定义dp[i] [j] :组合长度为i的所有方案,其中有多少种能凑出j
所以![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0htH4KHG-1655889351428)(C:\Users\lebronHArden\AppData\Roaming\Typora\typora-user-images\image-20220622164157562.png)]](/img/5d/8aad8e68678409f35fd2de6a21fe76.png)
所以可以直接上代码啦:
class Solution {
public int combinationSum4(int[] nums, int target) {
//dp[i][j]定义为组合长度为i的所有方案中有多少种能组成j
int[][] dp = new int[target+1][target+1];//想返回dp[target][target]
dp[0][0] = 1;
int ans = 0;
for(int i =1;i<=target;i++){
for(int j = 0; j<=target;j++){
for(int tmp:nums){
if(j>=tmp) dp[i][j] +=dp[i-1][j-tmp];
}
}
ans+=dp[i][target];
}
return ans;
}
}
上述代码就可以考虑到1,2和2,1的不同,二者都可以为结果做贡献这样.
考虑如何优化为一维:
应当考虑针对每个背包容量下:1,2和2,1视作不同的组合
class Solution {
public int combinationSum4(int[] nums, int target) {
//int n = nums.length;
//dp[i][j]定义为组合长度为i的所有方案中有多少种能组成j
int[] dp = new int[target+1];//想返回dp[target]
dp[0] = 1;
for(int i =1;i<=target;i++){
for(int tmp:nums){
if(i>=tmp) dp[i]+=dp[i-tmp];
}
}
return dp[target];
}
}
边栏推荐
- 运用span-method巧妙实现多层table数据的行合并
- [deeply understand tcapulusdb technology] tcapulusdb transaction management - error troubleshooting
- How to judge whether text is an array in the slot
- How should programmers look up dates
- R语言data.table导入数据实战:data.table数据列名称的重命名(rename)
- socket的connect函数用法
- 如何在 FlowUs和Notion 等笔记软件中进行任务管理?
- [deeply understand tcapulusdb technology] realize tcapulusdb transaction management in the operation and maintenance platform
- Mysql database knowledge points (III)
- 阿波罗使用注意事项
猜你喜欢

web技术分享| 【高德地图】实现自定义的轨迹回放

【深入理解TcaplusDB技术】入门Tcaplus SQL Driver

【深入理解TcaplusDB技术】入门TcaplusDB 问题汇总

Traversal of trees and forests
![[compréhension approfondie de la base de connaissances tcaplusdb] déploiement de la version locale de tcaplusdb FAQ](/img/2b/3ab5e247ac103728b4d3579c3c5468.png)
[compréhension approfondie de la base de connaissances tcaplusdb] déploiement de la version locale de tcaplusdb FAQ
![[in depth understanding of tcapulusdb technology] getting started with MySQL driver](/img/7b/8c4f1549054ee8c0184495d9e8e378.png)
[in depth understanding of tcapulusdb technology] getting started with MySQL driver
![[in depth understanding of tcaplus DB technology] getting started tcaplus SQL driver](/img/2b/3ab5e247ac103728b4d3579c3c5468.png)
[in depth understanding of tcaplus DB technology] getting started tcaplus SQL driver

Nlp-d57-nlp competition D26 & skimming questions D13 & reading papers & finding bugs for more than an hour
![[deeply understand tcapulusdb technology] view the online operation of tcapulusdb](/img/6f/2d62030e631e3085acf72951f2416f.png)
[deeply understand tcapulusdb technology] view the online operation of tcapulusdb

【深入理解TcaplusDB技术】入门Tcaplus-JDBC开发
随机推荐
Modify the antd tree component so that its subclasses are arranged horizontally.
Redis中的Multi事务
[deeply understand tcapulusdb technology] tcapulusdb model management
【深入理解TcaplusDB技术】入门Tcaplus SQL Driver
Mysql database knowledge points (III)
[deeply understand tcapulusdb technology] how to start tcapulusdb process
Random talk about redis source code onehundredandtwenty
Antd tree tree tree selector subclass required
图的存储结构(邻接矩阵)
Some problem records of openpnp using process
[deeply understand tcapulusdb technology] realize tcapulusdb transaction management in the operation and maintenance platform
芯和半导体“射频EDA/滤波器设计平台”闪耀IMS2022
Huffman tree (C language)
斐波那契查找(黄金分割)
【深入理解TcaplusDB技术】TcaplusDB常规单据
【深入理解TcaplusDB技术】单据受理之创建业务指南
漫话Redis源码之一百一二十
归并排序(递归和迭代实现)
拓扑排序
[petty bourgeoisie database] break down the concept: data, database, database system, database management system, database technology