LeetCode 面试题 08.11 硬币 题解
题目描述
硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)
示例1:
1 | 输入: n = 5 |
示例2:
1 | 输入: n = 10 |
算法1
(动态规划) $O(n^2)$
分析题意,不难看出这是一道经典的完全背包模型题
完全背包模型为:
- 共有
i
种物品,从中选出若干个装满体积为j
的背包,所能达到的最大价值,每种物品的体积为vi
, 价值为wi
- 每种物品可以选
0~无限个
完全背包的思考方式如下:
- 首先,要认识到每种方案的选择都是一类状态的结果,因此很容易想到需要使用
动态规划
- 其次,按照动态规划的思考路线,首先思考动态规划的递推数组含义:
- 由于数组是包含了物品种类
i
,物品体积j
两个因素,因此很容易想到需要使用二维数组来进行表示 - f[i][j]表示,从 i 种物品种选出体积为 j的方案的价值,在本题中,可以转换为:从前 i 种硬币中,选出组合为 j 的方案数
- 考虑递推关系,当选择
第 i 种
硬币时,可以选 0 个,1 个, 2 个, …,- 可得到递推关系式为:
f[i][j] = f[i - 1][j] + f[i - 1][j - vi] + f[i - 1][j - 2vi] + f[i - 1][j - 3vi] + ...
可以看到是一个具有明显递推性质的公式,那么尝试递推, 将j
替换为j - vi
:f[i][j - vi] = f[i - 1][j - vi] + f[i - 1][j - 2vi] + f[i -1][j - 3vi] + ...
- 通过递推关系,可以得到最终的递推式:
f[i][j] = f[i - 1][j] + f[i][j - 1]
- 可得到递推关系式为:
- 由于数组是包含了物品种类
- 最终,根据我们得到的递推式,可以写出动态规划的解题方法
1 | class Solution { |
算法2
(动态规划, 空间优化版本) $O(n^2)$
朴素版本的动态规划使用了$O(n^2)$的空间,但是这种空间有很多冗余,是可以进行优化的
观察我们的递推公式,在第一维 f[i]
中,所有的f[i]
都依赖于前一个f[i - 1]
,因此可以将f[i]
这一维优化掉:
f[i][j] = f[i - 1][j] + f[i][j - vi]
优化为:f[j] = f[j] + f[j - vi]
1 | class Solution { |
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.