题目难度: 中等

原题链接

今天继续更新程序员面试金典系列, 大家在公众号 算法精选 里回复 面试金典 就能看到该系列当前连载的所有文章了, 记得关注哦~

题目描述

硬币。给定数量不限的硬币,币值为 25 分、10 分、5 分和 1 分,编写代码计算 n 分有几种表示法。(结果可能会很大,你需要将结果模上 1000000007)

示例 1:

  • 输入: n = 5
  • 输出:2
  • 解释: 有两种方式可以凑成总金额:
    • 5=5
    • 5=1+1+1+1+1

示例 2:

  • 输入: n = 10
  • 输出:4
  • 解释: 有四种方式可以凑成总金额:
    • 10=10
    • 10=5+5
    • 10=5+1+1+1+1+1
    • 10=1+1+1+1+1+1+1+1+1+1

说明:

你可以假设:

0 <= n (总金额) <= 1000000

题目思考

  1. 如何利用已经计算出的结果?

解决方案

思路

  • 分析题目, 考虑得到 n 分的最后一枚硬币, 它可以是 25 分、10 分、5 分和 1 分
  • 也就是说, 要得到 n 分的表示法, 只需要累加 n-25, n-10, n-5 以及 n-1 的方案数
  • 所以我们可以利用动态规划的思路, 累加之前的结果, 求出每一分的表示方案数, 最终 n 分的方案数即为所求
  • 具体做法就是, 对于每一种硬币 c, 计算从 c 到 n 分的表示方案数, 对于每个总和 sm, 都有 dp[sm]=dp[sm]+dp[sm-c] (c<=sm<=n)
  • 另外注意初始化 0 分的方案数为 1, 代表什么硬币都不用的情况

复杂度

  • 时间复杂度 O(NC): 外层循环遍历每种硬币, 内层循环遍历总和, 所以是 N*C (C 是硬币种类数)
  • 空间复杂度 O(N): 使用了一个长度为 N 的数组存各个总和的方案数

代码

class Solution:
    def waysToChange(self, n: int) -> int:
        # 动态规划, dp[sm]存总和为sm的方案数
        # 对于每一种硬币c, 都有dp[sm]=dp[sm]+dp[sm-c] (c<=sm<=n)
        MOD = 1000000007
        coins = [1, 5, 10, 25]
        dp = [1] + [0] * n
        for c in coins:
            for sm in range(c, n + 1):
                dp[sm] = (dp[sm] + dp[sm - c]) % MOD
        return dp[n]

大家可以在下面这些地方找到我~😊

我的 GitHub

我的 Leetcode

我的 CSDN

我的知乎专栏

我的头条号

我的牛客网博客

我的公众号: 算法精选, 欢迎大家扫码关注~😊

算法精选 - 微信扫一扫关注我