返回

硬币找零问题的最优解

前端

问题阐述

硬币找零问题在日常生活中很常见。比如,我们去商店购物,使用不同面额的硬币找零时,如何才能用最少的硬币找齐零钱?

解决方案

硬币找零问题有多种求解方法,其中动态规划和贪心算法是两种最常用的方法。

动态规划

动态规划的核心思想是将问题分解成一系列子问题,然后逐步求解这些子问题,最终得到问题的整体解。对于硬币找零问题,我们可以定义一个二维数组 dp[i][j],其中 dp[i][j] 表示使用前 i 个硬币凑成金额 j 所需的最少硬币数。

def coin_change_dp(coins, amount):
    dp = [[float('inf')] * (amount + 1) for _ in range(len(coins) + 1)]
    
    # 初始化
    for i in range(len(coins) + 1):
        dp[i][0] = 0
    
    # 递推
    for i in range(1, len(coins) + 1):
        for j in range(1, amount + 1):
            if coins[i - 1] <= j:
                dp[i][j] = min(dp[i - 1][j], 1 + dp[i][j - coins[i - 1]])
            else:
                dp[i][j] = dp[i - 1][j]
    
    return dp[len(coins)][amount]

贪心算法

贪心算法是一种每次做出局部最优解,从而逐步逼近全局最优解的算法。对于硬币找零问题,贪心算法的做法是每次选择面额最大的硬币,直到凑齐总金额。

def coin_change_greedy(coins, amount):
    coins.sort(reverse=True)
    result = []
    
    for coin in coins:
        while amount >= coin:
            amount -= coin
            result.append(coin)
    
    return len(result)

效率分析

时间复杂度:

  • 动态规划:O(n * m),其中 n 为硬币种类数,m 为总金额。
  • 贪心算法:O(n log n),其中 n 为硬币种类数。

空间复杂度:

  • 动态规划:O(n * m)
  • 贪心算法:O(1)

总结

硬币找零问题是编程面试中经常遇到的问题。通过理解动态规划和贪心算法的原理,我们可以高效地求解此类问题。