首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

leetcode 518. 零钱兑换 II-----完全背包套路模板

同时硬币相当于我们物品,每种硬币可以选择「无限次」,自然想到「完全背包」。...<= amount; j++) { dp[j] += dp[j - val]; } } return dp[amount]; } }; ---- 注意双重for循环顺序...下标非0dp[j]初始化为0,这样累计加dp[j - coins[i]]时候才不会影响真正dp[j] 4.确定遍历顺序 本题中我们是外层for循环遍历物品(钱币),内层for遍历背包(金钱总额),...完全背包两个for循环先后顺序都是可以。 但本题就不行了! 因为纯完全背包求得是能否凑成总和,和凑成总和元素有没有顺序没关系,即:有顺序也行,没有顺序也行!...那么本题,两个for循环先后顺序可就有说法了。 我们先来看 外层for循环遍历物品(钱币),内层for遍历背包(金钱总额)情况。

35340

动态规划:给你一些零钱,你要怎么凑?

那我为什么要介绍这些呢,因为这和下文讲解遍历顺序息息相关!...下标非0dp[j]初始化为0,这样累计加dp[j - coins[i]]时候才不会影响真正dp[j] 确定遍历顺序 本题中我们是外层for循环遍历物品(钱币),内层for遍历背包(金钱总额),还是外层...中讲解了完全背包两个for循环先后顺序都是可以。 但本题就不行了! 因为纯完全背包求得是能否凑成总和,和凑成总和元素有没有顺序没关系,即:有顺序也行,没有顺序也行!...那么本题,两个for循环先后顺序可就有说法了。 我们先来看 外层for循环遍历物品(钱币),内层for遍历背包(金钱总额)情况。...此时dp[j]里算出来就是排列数! 可能这里很多同学还不是理解,建议动手把这两种方案dp数组数值变化打印出来,对比看一看!

1.3K10
您找到你想要的搜索结果了吗?
是的
没有找到

动态规划: 给我个机会,我再兑换一次零钱

代码如下: vector dp(amount + 1, INT_MAX); dp[0] = 0; 确定遍历顺序 本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币最小个数。。...所以本题两个for循环关系是:外层for循环遍历物品,内层for遍历背包或者外层for遍历背包,内层for循环遍历物品都是可以! 那么我采用coins放在外循环,target在内循环方式。...所以遍历循环是正序 综上所述,遍历顺序为:coins(物品)放在外循环,target(背包)在内循环。且内循环正序。...但最终又可以稀里糊涂把题目过了,也不知道为什么这样可以过,反正就是过了,哈哈 那么这篇文章就把遍历顺序分析清清楚楚。 动态规划:518.零钱兑换II中求是组合数,动态规划:377....这也是我为什么要先讲518.零钱兑换II 然后再讲本题即:322.零钱兑换,这是Carl良苦用心那。 相信大家看完之后,对背包问题中遍历顺序又了更深理解了。

46410

本周小结!(动态规划系列五)

如果把遍历nums(物品)放在外循环,遍历target作为内循环的话,举一个例子:计算dp[4]时候,结果集只有 {1,3} 这样集合,不会有{3,1}这样集合,因为nums遍历放在外层,3只能出现在...所以本题遍历顺序最终遍历顺序:target(背包)放在外循环,将nums(物品)放在内循环,内循环从前到后遍历。...递归公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j]); 关键看遍历顺序。 本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币最小个数。。...那么本题两个for循环关系是:外层for循环遍历物品,内层for遍历背包或者外层for遍历背包,内层for循环遍历物品都是可以!...零钱兑换 一样一样。 要是没有前面的基础上来做这道题,那这道题目就有点难度了。 这也体现了刷题顺序重要性。

61620

动态规划详解(修订版)

解决一个子问题时间,同上,没有什么循环,时间为 O(1)。 所以,本算法时间复杂度是 O(n)。比起暴力算法,是降维打击。 至此,带备忘录递归解法效率已经和迭代动态规划一样了。...反过来,我们直接从最底下,最简单,问题规模最小f(1)和f(2)开始往上推,直到推到我们想要答案f(20),这就是动态规划思路,这也是为什么动态规划一般都脱离了递归,而是由循环迭代完成计算。...可见列出「状态转移方程」重要性,它是解决问题核心。容易发现,其实状态转移方程直接代表着暴力解法。 千万不要看不起暴力解,动态规划问题最困难就是写出状态转移方程,即这个暴力解。...然后确定dp函数定义:函数 dp(n)表示,当前目标金额是n,至少需要dp(n)个硬币凑出该金额。 然后确定「选择」并择优,也就是对于每个状态,可以做出什么选择改变当前状态。...3、dp 数组迭代解法 当然,我们也可以自底向上使用 dp table 来消除重叠子问题,dp数组定义和刚才dp函数类似,定义也是一样dp[i] = x表示,当目标金额为i时,至少需要x枚硬币

53650

再来聊一聊「动态规划」

至于为什么最终解法看起来如此精妙,是因为动态规划遵循一套固定流程:递归暴力解法 -> 带备忘录递归解法 -> 非递归动态规划解法。...解决一个子问题时间,同上,没有什么循环,时间为 O(1)。 所以,本算法时间复杂度是 O(n)。比起暴力算法,是降维打击。 至此,带备忘录递归解法效率已经和动态规划一样了。...反过来,我们直接从最底下,最简单,问题规模最小 f(1) 和 f(2) 开始往上推,直到推到我们想要答案 f(20),这就是动态规划思路,这也是为什么动态规划一般都脱离了递归,而是由循环迭代完成计算...可见列出「状态转移方程」重要性,它是解决问题核心。容易发现,其实状态转移方程直接代表着暴力解法。 千万不要看不起暴力解,动态规划问题最困难就是写出状态转移方程,即这个暴力解。...int coin : coins) { if (i - coin < 0) continue; dp[i] = min(dp[i], 1 + dp[i -

64620

计算机解决问题没有奇技淫巧,但动态规划还是有点套路

至于为什么最终解法看起来如此精妙,是因为动态规划遵循一套固定流程:递归暴力解法 -> 带备忘录递归解法 -> 非递归动态规划解法。...反过来,我们直接从最底下,最简单,问题规模最小 f(1) 和 f(2) 开始往上推,直到推到我们想要答案 f(20),这就是动态规划思路,这也是为什么动态规划一般都脱离了递归,而是由循环迭代完成计算...可见列出「状态转移方程」重要性,它是解决问题核心。容易发现,其实状态转移方程直接代表着暴力解法。 千万不要看不起暴力解,动态规划问题最困难就是写出状态转移方程,即这个暴力解。...int sum = prev + curr; prev = curr; curr = sum; } return curr;} 有人会问,动态规划另一个重要特性...coin : coins) { if (i - coin < 0) continue; dp[i] = min(dp[i], 1 + dp[i - coin

40220

DP】518. Coin Change 2

因为是要找组合方案数,所以对于 (1 2)、(2 1) 这种其实是一样,所以我们外层循环应该是 coin,即 for coin in coins(这样就避免出现排列问题)。...那么,内层循环 j 就是用 当前 coin 去更新这个 dp 数组中方案数。...转移方程式可以想到:dp[j] = dp[j-coins[i]],但是因为外层循环每个 coins[i] 都可能更新这个 dp[j],因此最终转移方程式应该为: dp[j] = ∑ dp[j-coins...∑ 次数等于外层循环次数。 记得初始化 dp[0] = 1,表示总额为 0 时方案数为 1。其他位置 dp[j] 初始化为 0。...比如 (1 2)和 (2 1)是不同情况。那么该怎么去做? 其实,这个问题是 Leetcode 另一道题: 【377】给一个数组和一个目标,求合成目标的不同组合数,与顺序有关

43330

动态规划详解

至于为什么最终解法看起来如此精妙,是因为动态规划遵循一套固定流程:递归暴力解法 -> 带备忘录递归解法 -> 非递归动态规划解法。...解决一个子问题时间,同上,没有什么循环,时间为 O(1)。 所以,本算法时间复杂度是 O(n)。比起暴力算法,是降维打击。 至此,带备忘录递归解法效率已经和动态规划一样了。...反过来,我们直接从最底下,最简单,问题规模最小 f(1) 和 f(2) 开始往上推,直到推到我们想要答案 f(20),这就是动态规划思路,这也是为什么动态规划一般都脱离了递归,而是由循环迭代完成计算...可见列出「状态转移方程」重要性,它是解决问题核心。容易发现,其实状态转移方程直接代表着暴力解法。 千万不要看不起暴力解,动态规划问题最困难就是写出状态转移方程,即这个暴力解。...int coin : coins) { if (i - coin < 0) continue; dp[i] = min(dp[i], 1 + dp[i -

3.3K85

leetcode 322. 零钱兑换

所需要最少硬币数没有算出来, //但是注意我们最外层循环已经说了,是从最小1开始往上直到amount,一层层求出每个所需要最少硬币数 //既然i-coin比i小,并且dp[i-coin...-1 : res; } }; ---- 4.套「完全背包」问题公式 为什么是「完全背包」问题: 每个硬币可以使用无限次; 硬币总额有限制; 并且具体组合是顺序无关,还以示例 1 为例:面值总额为...所以在代码里:外层循环先遍历是硬币面值,内层循环遍历是面值总和。 这里我先举一个例子: 我们有1,2,5面值硬币,我们要凑出11元,最少需要多少硬币?...,接着我从钱包中拿出了5个2元硬币,放入了2个五元硬币,最终我成功逃了出来,钱包中硬币个数为3,分别为5,5,1 由上面这个瞎编例子可以看出外层循环硬币面值和内存循环遍历面值总和作用,首先外层遍历面值...,是会随着发现不同硬币而做出不同选择而发生改变 //可能选择后硬币数会更少,也可能会更多 dp[i] = min(dp[i], dp[i - coin] + 1); } }

35110

算法时空复杂度分析实用指南

比如前文 动态规划核心框架 中讲到凑零钱问题暴力递归解法,核心代码框架如下: // 定义:要凑出金额 n,至少要 dp(coins, n) 个硬币 int dp(int[] coins, int amount...你看dp函数里面有个 for 循环遍历长度为Kcoins列表,所以函数本身复杂度为O(K),故该算法总时间复杂度为: O(K^N) * O(K) = O(K^(N+1)) 当然,之前也说了,这个复杂度只是一个粗略上界...这个算法空间复杂度容易分析: dp函数本身没有申请数组之类,所以算法申请存储空间为O(1);而dp函数堆栈深度为递归树高度O(N),所以这个算法空间复杂度为O(N)。...如果你把自顶向下带备忘录解法进一步改写成自底向上迭代解法: int coinChange(int[] coins, int amount) { // 空间 O(N) int[] dp...O(N),但该算法实际空间消耗是更小,所以自底向上迭代动态规划是各方面性能最好

1.3K40

力扣每日一刷(2023.9.14)

, 1) (2, 2) (3, 1) 请注意,顺序不同序列被视作不同组合。...按照动规思路dp[i] : 表示总和为i组合个数为dp[i] 还有需要注意就是遍历顺序, 一般来说对于背包问题: **求组合是外层遍历物品,内层遍历背包。...dp[i]:表示 可以凑成总金额 i 所需 最少硬币个数为dp[i] 这道题对于遍历位次顺序要求就没那么高了, 先遍历背包或者物品都行 ,这里我用先遍历物品(习惯)。...所以**dp[i]: 可以表示 和为 i 完全平方数最少数量是dp[i]** 遍历顺序还是使用先物品 后背包方式, 如果物品重量 > 背包容量。...递推公式中dp[i-len] == true ,需要判断上一个循环是否满足条件 if(i>= len && dp[i-len] && str.equals(s.substring

9010

一个模板搞定各种背包问题

遍历行时顺序也即访问每件物品顺序,虽然物品顺序不作限制,但这里有个隐藏条件,遍历过物品是不会再次访问,也就是说,选择物品是组合问题,无论先选哪个后选哪个,只要都被选了,只能算作一种状态。...不用加重记忆负担去考虑什么时候该顺序遍历,什么时候该逆序遍历,以及行列遍历顺序能不能颠倒。当你了解了这个模板含义,知道动态规划是如何在二维数组上实现,这些问题都可以迎刃而解。..., 1) (2, 2) (3, 1) 请注意,顺序不同序列被视作不同组合。...]和dp[i][j-coins[i-1]]+1较小值,这里是赋值而非累加 if j>=coins[i-1]: # dp[i][j]=min(dp[i...(s)+1) for _ in range(n)] dp[0][0]=True for j in range(len(s)+1): #内外循环颠倒,按列遍历(单词可以不在乎顺序,和排列类似

40710

JS算法之动态规划

」,可以方便将它转换成递归代码。...1] = cost[1]; 用一个for循环根据状态转移方程逐一求解f(2)到f(n-1) 时间复杂度和空间复杂度都是O(n) ---- 空间复杂度为O(1)迭代代码 用一个长度为n数组将所有f(i...❞ 先将表格中i等于-1对应行和j等于-1对应列都初始化为0 然后按照「从上到下、从左到右」顺序填充表格中其他位置 「先用一个二维数组实现这个表格,然后用一个二重循环实现从上到下、从左到右填充顺序...f(i,j)保存在dp[i][j]中 ---- 迭代代码 如果将二维数组dp看成一个表格,在初始化表格「第1行(行号为0)和第1列(列号0)之后」,可以按照「从左到右、从上到下」顺序填充表格其他位置...仍然用一个二重循环按照状态转移方程计算 循环体内dp[j]+=dp[j-1]可以看成dp[j]= dp[j]+dp[j-1] 在赋值运算符「右边」 dp[j]保存是f(i-1,j),dp[j-1]

6.1K11

DP、BFS】322. Coin Change

因此,贪心思想行不通。 方法1:动态规划(DP) 这道题首先就会想到用完全背包思想来求解。参考之前写文章: 01-背包、完全背包、多重背包及其相关应用。...因此,我们只需要创建一个大小为 dp[amount+1] 数组,dp[j] 表示兑换 j 块钱所需要最少硬币数。...外层循环是对 coins 遍历,即 for coin in coins,内层循环 j 状态转移方程只需要将完全背包中 dp[j] = max(dp[j], dp[j-w[i]] + v[i]) 对应替换为...如果最后 dp[-1] == float("inf"),说明不能兑换 amount,应该返回 -1,否则,dp[-1] 就是最后答案。...().coinChange([4,3], 14)) # 4 方法2:广度优先搜索(BFS) 这道题和这样题目类似:一个人要从原点 0 走到 amount,每一次有不同走法,求走到 amount 所需要最少步数

72130

​LeetCode刷题实战518:零钱兑换 II

算法重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !...(前 i 个硬币即 coins[0]、…、coins[i-1])   在计算 dp[i][j] 时有两个选择:   1、一定不包含第 i-1 个硬币,此时 dp[i][j] = dp[i-1][j],即让前...i-1 硬币去组成金额 j;   2、一定包含第 i-1 个硬币,此时 dp[i][j] = dp[i][j-coins[i-1]],即已经包含了第 i-1 个硬币,此时金额剩下 j-coins[i...设 dp[j] 表示对于硬币组成金额 j 组合数。   虽然状态变成了一个,但是还是得有两层 for 循环遍历,外层是前 i 个硬币,内层是金额。   ...当 j-coins[i-1] ≥ 0 时,说明第 i-1 个硬币属于可选可不选,dp[j] = dp[j] + dp[j-coins[i-1]],第一个加数为不包含,第二个加数为包含。

18110

数据结构和算法学习指南

为什么要先刷二叉树呢,因为二叉树是最容易培养框架思维,而且大部分算法技巧,本质上都是树遍历问题。 刷二叉树看到题目没思路?...动态规划详解 说过凑零钱问题,暴力解法就是遍历一棵 N 叉树: def coinChange(coins: List[int], amount: int): def dp(n):...直接提取出框架,就能看出核心思路了: # 不过是一个 N 叉树遍历问题而已 def dp(n): for coin in coins: dp(n - coin) 其实很多动态规划问题就是在遍历一棵树...你说,树这种结构重不重要? 综上,对于算法无从下手朋友来说,可以先刷树相关题目,试着从框架上看问题,而不要纠结于细节问题。...四、最后总结 数据结构基本存储方式就是链式和顺序两种,基本操作就是增删查改,遍历方式无非迭代和递归。 刷算法题建议从「树」分类开始刷,结合框架思维,把这几十道题刷完,对于树结构理解应该就到位了。

35040
领券