这题和完全背包问题相似,不同处在于这题要求容积要恰好填满,但是完全背包问题只要求“不超过”,并且这题要求的是方案数,而完全背包问题要求一个小于容积的最大值。首先尝试用填满二维表格的方法,我们设f[i][j]为考虑前i种硬币,凑出金额为j的最少数目。考虑第i种硬币,我们可以不拿,或者拿i…k个,直到超出总金额。f[i][j] = min(f[i-1][j], f[i-1][j-c]+1, f[i-1][j-2c]+2, …, f[i-1][j-kc]+k),又因为其中包含了大量冗余的运算,例如: f[i][j-c] = min(f[i-1][j], f[i-1][j-2c]+1, …, f[i-1][j-kc]+(k-1)),将两者合并可以得到f[i][j] = min(f[i-1][j], f[i][j-c]+1)。我们将该思路用代码实现出来,如1所示,其中需要注意的是当j小于当前考虑的硬币都面值的时候,我们要直接将上一行的数据复制下来。这样直到计算出最右下角的元素即为最小需要硬币的数量。这个方法的时间复杂度是O(NM),空间复杂度是O(NM),其中N为零钱种类,M为金额。
考虑到f[i][j]只和上一层的一个状态f[i-1][j]以及这一层的一个状态f[i][j-c]+1有关,我们可以将状态优化为一维数组。如2所示,此时我们将空间复杂降低为了O(M)。因为金额从小到大枚举,所以计算j时,j-c的状态已经计算好了,可以直接替换。这里恰好是与0-1背包问题相反的。
python:
PREVIOUSlc516.最长回文子序列
NEXTlc032.最长有效括号