动态规划解题套路框架 :: labuladong的算法小抄 #1006
Replies: 93 comments 21 replies
-
哇!真是太奇妙了,虽然我没看懂 |
Beta Was this translation helpful? Give feedback.
-
这里有个疑问,如果是(1,2,3,5)这四种币种,amount=18,那么amount=17的最优解是5+5+5+2,然后再加1枚1元组成18,这样用了5枚,但这并不是最优解。因为5+5+5+3=18,这是最优解。所以我觉得子问题互相独立这个说法欠妥。 |
Beta Was this translation helpful? Give feedback.
-
@argosdh 你理解错了,你说的只是其中一种情况 |
Beta Was this translation helpful? Give feedback.
-
@argosdh 18的最优子解,不一定是17的最优解 |
Beta Was this translation helpful? Give feedback.
-
牛啊牛啊 |
Beta Was this translation helpful? Give feedback.
-
@argosdh 5+5+5+3的情况在dp(18-3)里面了 |
Beta Was this translation helpful? Give feedback.
-
@dlseal ” 回到凑零钱问题,为什么说它符合最优子结构呢?比如你想求 amount = 11 时的最少硬币数(原问题),如果你知道凑出 amount = 10 的最少硬币数(子问题),你只需要把子问题的答案加一(再选一枚面值为 1 的硬币)就是原问题的答案。因为硬币的数量是没有限制的,所以子问题之间没有相互制,是互相独立的。“ 这句话的意思不就是 18的最优解 = 17的最优解 + 1 吗? |
Beta Was this translation helpful? Give feedback.
-
@argosdh dp数组(函数)的结果是用的钱币数而不是amount总值,变量(状态)才是amount总值,所以状态转移方程是min(1+dp[i-coin],dp[i]),说的是每次做好选择的钱币数之间是互相独立 |
Beta Was this translation helpful? Give feedback.
-
作者关于凑零钱的最优子结构描述确实有些问题,至少从读者角度是有些费解的,私以为可以这样理解这里的子问题,要凑够amount,就要选硬币,c1至ck总要至少选一个,则选每种的最小个数是1+dp[amount-ci],我们把每种硬币都选一遍,答案即为其中的最小值 |
Beta Was this translation helpful? Give feedback.
-
666 还需要多多练习啊 |
Beta Was this translation helpful? Give feedback.
-
凑零钱的最优子结构描述 读者理解起来很费解。我和上面几位同学有相同的疑问? 可能还是没深刻理解 |
Beta Was this translation helpful? Give feedback.
-
我经常看到有人搞不清楚子问题的结果为什么是加 1,而不是加硬币金额之类的。我这里统一提示一下,动态规划问题的关键是 |
Beta Was this translation helpful? Give feedback.
-
一定有面值为1的硬币吗? |
Beta Was this translation helpful? Give feedback.
-
😯 懂了 ,忽略忽略 |
Beta Was this translation helpful? Give feedback.
-
斐波那契,备忘录,看不太懂,但是dp看的懂 |
Beta Was this translation helpful? Give feedback.
-
看了文章之后,独立刷出来了。赞!! |
Beta Was this translation helpful? Give feedback.
-
aaa |
Beta Was this translation helpful? Give feedback.
-
有点刻意秀递归了,像硬币这种题,关键怎么知道是二元dp问题,什么时候是一元dp问题,子问题怎么找的就一笔带过,这部分真不如去看 leecode 官解 |
Beta Was this translation helpful? Give feedback.
-
暴力遞歸的空間複雜度也是 O(n) 嗎? |
Beta Was this translation helpful? Give feedback.
-
回到凑零钱问题,为什么说它符合最优子结构呢?假设你有面值为 1, 2, 5 的硬币,你想求 amount = 11 时的最少硬币数(原问题),如果你知道凑出 amount = 10, 9, 6 的最少硬币数(子问题),你只需要把子问题的答案加一(再选一枚面值为 1, 2, 5 的硬币),求个最小值,就是原问题的答案。因为硬币的数量是没有限制的,所以子问题之间没有相互制,是互相独立的。 |
Beta Was this translation helpful? Give feedback.
-
322零钱兑换Python版打卡 class Solution:
def dp(self,memo,amount,coins):
if amount==0:
return 0
if amount<0:
return -1
if memo[amount]!=1000:
return memo[amount]
res=float('inf')
for coin in coins:
subProblem=self.dp(memo,amount-coin,coins)
if subProblem==-1:
continue
res=min(res,subProblem+1)
memo[amount] = -1 if res == float('inf') else res
return memo[amount]
def coinChange(self, coins: List[int], amount: int) -> int:
memo=[1000]*(amount+1)
return self.dp(memo,amount,coins) |
Beta Was this translation helpful? Give feedback.
-
子问题总数,严格来讲应该是递归树的【中间】节点个数吧?不包括叶节点 |
Beta Was this translation helpful? Give feedback.
-
dp解法明白。但是备忘录解法原理能明白,代码却像天外来物,暂时还不能内化。感谢博主,收获颇丰。 |
Beta Was this translation helpful? Give feedback.
-
自底向上动规js解法 |
Beta Was this translation helpful? Give feedback.
-
有读研的还不会的么 |
Beta Was this translation helpful? Give feedback.
-
这2个例子理解入门挺好的,学习了 |
Beta Was this translation helpful? Give feedback.
-
凑硬币 //dpArray表示凑齐amount所需最少硬币个数
//状态转移方程 dp[i]=dp[0...coins]
public int dpArray(int[]coins,int amount){
int[]dp=new int[amount+1];
for(int i=1;i<=amount;i++){
dp[i]=Integer.MAX_VALUE;
for(int j=0;j<coins.length;j++){
int val=coins[j];
//由0--i-1的去凑
if(i-val>=0&&dp[i-val]>=0){
dp[i]=Math.min(dp[i-val]+1,dp[i]);
}
}
dp[i]=dp[i]==Integer.MAX_VALUE?-1:dp[i];
}
return dp[amount];
} |
Beta Was this translation helpful? Give feedback.
-
想请教一下大家为什么凑零钱问题不能用贪心算法来解?我第一感觉是贪心,因为想要硬币数最少,那就总是先使用面额大的硬币来凑? |
Beta Was this translation helpful? Give feedback.
-
【 本文代码: int coinChange(int[] coins, int amount) {
// 题目要求的最终结果是 dp(amount)
return dp(coins, amount)
}
// 定义:要凑出金额 n,至少要 dp(coins, n) 个硬币
int dp(int[] coins, int amount) {
// base case
if (amount == 0) return 0;
if (amount < 0) return -1;
int res = Integer.MAX_VALUE;
for (int coin : coins) {
// 计算子问题的结果
int subProblem = dp(coins, amount - coin);
// 子问题无解则跳过
if (subProblem == -1) continue;
// 在子问题中选择最优解,然后加一
res = Math.min(res, subProblem + 1);
}
return res == Integer.MAX_VALUE ? -1 : res;
} 上述代码里的 万一以为此判断只处理了场景1,不用数值-1来识别(例如改用-100),则无法处理场景2: int dp(int[] coins, int amount) {
...
if (amount < 0) return -100;
int res = Integer.MAX_VALUE;
for (int coin : coins) {
int subProblem = dp(coins, amount - coin);
if (subProblem == -100) continue;
...
}
return res == Integer.MAX_VALUE ? -1 : res;
} 可读性更高的写法,是进入recursion前就以 int coinChange(int[] coins, int amount) {
int res = dp(coins, amount)
return res == Integer.MAX_VALUE ? -1 : res;
}
int dp(int[] coins, int amount) {
if (amount == 0) return 0;
int res = Integer.MAX_VALUE;
for (int coin : coins) {
if (amount >= coin) {
int subProblem = dp(coins, amount - coin);
res = Math.min(res, subProblem + 1);
}
}
return res;
} |
Beta Was this translation helpful? Give feedback.
-
东哥,递推解法框架是不是应该修改为下面的样子,原文应该是笔误了
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
文章链接点这里:动态规划解题套路框架
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions