fucking-algorithm icon indicating copy to clipboard operation
fucking-algorithm copied to clipboard

动态规划解题套路框架 :: labuladong的算法小抄

Open utterances-bot opened this issue 3 years ago • 51 comments

文章链接点这里:动态规划解题套路框架

评论礼仪 见这里,违者直接拉黑。

utterances-bot avatar Nov 23 '21 02:11 utterances-bot

哇!真是太奇妙了,虽然我没看懂

jizhigang avatar Nov 23 '21 02:11 jizhigang

这里有个疑问,如果是(1,2,3,5)这四种币种,amount=18,那么amount=17的最优解是5+5+5+2,然后再加1枚1元组成18,这样用了5枚,但这并不是最优解。因为5+5+5+3=18,这是最优解。所以我觉得子问题互相独立这个说法欠妥。

argosdh avatar Nov 24 '21 14:11 argosdh

@argosdh 你理解错了,你说的只是其中一种情况

daydaystudylab avatar Nov 26 '21 05:11 daydaystudylab

@argosdh 18的最优子解,不一定是17的最优解

dlseal avatar Dec 02 '21 00:12 dlseal

牛啊牛啊

coder-pig avatar Dec 14 '21 07:12 coder-pig

@argosdh 5+5+5+3的情况在dp(18-3)里面了

yancewang avatar Dec 20 '21 15:12 yancewang

@dlseal ” 回到凑零钱问题,为什么说它符合最优子结构呢?比如你想求 amount = 11 时的最少硬币数(原问题),如果你知道凑出 amount = 10 的最少硬币数(子问题),你只需要把子问题的答案加一(再选一枚面值为 1 的硬币)就是原问题的答案。因为硬币的数量是没有限制的,所以子问题之间没有相互制,是互相独立的。“ 这句话的意思不就是 18的最优解 = 17的最优解 + 1 吗?

jiangshiyong1 avatar Dec 24 '21 08:12 jiangshiyong1

@argosdh dp数组(函数)的结果是用的钱币数而不是amount总值,变量(状态)才是amount总值,所以状态转移方程是min(1+dp[i-coin],dp[i]),说的是每次做好选择的钱币数之间是互相独立

Money8888 avatar Dec 25 '21 04:12 Money8888

作者关于凑零钱的最优子结构描述确实有些问题,至少从读者角度是有些费解的,私以为可以这样理解这里的子问题,要凑够amount,就要选硬币,c1至ck总要至少选一个,则选每种的最小个数是1+dp[amount-ci],我们把每种硬币都选一遍,答案即为其中的最小值

spadan avatar Dec 31 '21 02:12 spadan

666 还需要多多练习啊

a572251465 avatar Jan 12 '22 02:01 a572251465

凑零钱的最优子结构描述 读者理解起来很费解。我和上面几位同学有相同的疑问? 可能还是没深刻理解

daifaming-0107 avatar Jan 29 '22 07:01 daifaming-0107

我经常看到有人搞不清楚子问题的结果为什么是加 1,而不是加硬币金额之类的。我这里统一提示一下,动态规划问题的关键是 dp 函数/数组的定义,你这个函数的返回值代表什么?搞清楚这一点,然后就知道该怎么操作这个返回值了。

labuladong avatar Feb 02 '22 11:02 labuladong

一定有面值为1的硬币吗?

zzuuoo avatar Feb 07 '22 09:02 zzuuoo

😯 懂了 ,忽略忽略

zzuuoo avatar Feb 07 '22 09:02 zzuuoo

斐波那契,备忘录,看不太懂,但是dp看的懂

Yuzong-LYZ avatar Feb 18 '22 07:02 Yuzong-LYZ

子问题总数为递归树节点个数,这个比较难看出来,是 O(n^k),总之只要是树形结构,节点个数必然是是指数级别的。每个子问题中含有一个 for 循环,复杂度为 O(k)。所以总时间复杂度为 O(k * n^k),指数级别。

n 層 k 叉樹的節點數量應該是(k^n-1)/k-1, 為甚麼此遞歸樹,不是 O (k^n)?

ngokchaoho avatar Mar 26 '22 15:03 ngokchaoho

2022.3.28 mark

billgoo avatar Mar 28 '22 08:03 billgoo

迭代+备忘录:记忆化搜索(自顶向下的dp);for循环:自顶向上的dp。为什么要加1?因为dp表示求硬币最少数量。

gfu-Ac avatar Mar 31 '22 04:03 gfu-Ac

问一下509题第二种解法为啥初始化dp数组的长度是 n+1?

jingren-upup avatar Apr 01 '22 21:04 jingren-upup

@jiangshiyong1 假设有1,2,3三种硬币,18的最优解是(15、16、17)最优解的那一个+1次(+1硬币,+2硬币,+3硬币)

Nao-Chu avatar Apr 02 '22 06:04 Nao-Chu

零钱问题中为什么要初始dp数组为-666特殊值?不初始化(默认都是0) 的话,也一样可以啊

ningguo99 avatar Apr 03 '22 13:04 ningguo99

@ningguo99 备忘录需要初始化为一个不会被取到的特殊值,代表还未被计算。因为 if (amount == 0) return 0; 单独处理了 0 这种情况,所以 memo 初始化为 0 也可以认为是一个特殊值。

labuladong avatar Apr 04 '22 09:04 labuladong

@labuladong,节点总数哪里算错了吧,最坏情况下不是k^(n-1),那只是倒数第二层的节点数

cillian-bao avatar Apr 05 '22 08:04 cillian-bao

@cillian-bao 对,感谢指正,我改下。高度为 h 的满 k 叉树,最后一层节点数为 k^(h-1),总的节点数应该为 k^h - 1

labuladong avatar Apr 06 '22 07:04 labuladong

精妙 虽然我没有完全理解 但是的确用最简单的语言 把相对复杂的问题解释的很清楚 点赞

jennyliulfm avatar Apr 08 '22 10:04 jennyliulfm

打卡!

Sm1lence avatar Apr 19 '22 01:04 Sm1lence

凑零钱问题,如果是无解的情况,备忘录就不起作用了,时间复杂度就是O(k^n)了

neteric avatar Apr 30 '22 03:04 neteric

@neteric 如果你不确定,就不要说的这么笃定。无解的情况也被记在备忘录中,备忘录依然能够起到剪枝作用。

labuladong avatar May 02 '22 04:05 labuladong

“回到凑零钱问题,为什么说它符合最优子结构呢?假设你有面值为 1, 2, 5 的硬币,你想求 amount = 11 时的最少硬币数(原问题),如果你知道凑出 amount = 10, 9, 6 的最少硬币数(子问题),你只需要把子问题的答案加一(再选一枚面值为 1 的硬币),求个最小值,就是原问题的答案。因为硬币的数量是没有限制的,所以子问题之间没有相互制,是互相独立的。” 括号里的“再选一枚面值为1的硬币”,感觉描述有些问题,应该是在子问题的基础之上选一枚能满足原问题的面值硬币,比如10,9,6最少硬币数是子问题6的硬币数目,那么这里应该选面值为5的硬币。虽然我能理解作者能表达的意思~但第一次读到这还是困惑了很久。

SatireY avatar May 11 '22 03:05 SatireY

@SatireY 感谢指出,我优化一下表述

labuladong avatar May 12 '22 02:05 labuladong