返回
独辟蹊径:刷穿 LeetCode 322,解谜零钱兑换的“艺术”
见解分享
2023-09-12 15:45:45
在程序员的征战江湖中,算法问题宛如一座座险峻山峰,等待着我们披荆斩棘,步步攀登。而作为算法训练圣地的 LeetCode,其第 322 题——零钱兑换,更是一颗耀眼的明珠,吸引着无数勇士前来挑战。
在这场智力的角逐中,我们需要施展巧思,游刃有余地应对不同面额硬币和目标金额的组合,才能找寻到凑成目标金额的最少硬币数。
思路漫步:从贪心到动态规划
初遇此题,许多初学者往往会陷入贪心的误区。他们试图每次都选择面额最大的硬币,以为这样能够快速凑成目标金额。然而,这样的做法往往会事倍功半,甚至陷入死胡同。
真正的破局之道在于动态规划。我们将问题拆解成更小的子问题,逐步求解,最终拼凑出问题的全局最优解。具体而言,对于每个子问题,我们考虑使用不同面额的硬币来凑成目标金额,并记录下最少硬币数。
算法演绎:步步为营,层层递进
设 dp[i] 为凑成金额 i 所需的最少硬币数,其中 dp[0] = 0。对于目标金额为 i,我们枚举所有面额小于 i 的硬币,并计算使用这些硬币凑成 i 的最少硬币数。如果枚举到一个硬币 j 满足 j <= i 且 dp[i - j] + 1 < dp[i],则更新 dp[i] = dp[i - j] + 1。
代码画卷:精雕细琢,匠心独运
def coinChange(coins, amount):
# 初始化动态规划表
dp = [float('inf')] * (amount + 1)
dp[0] = 0
# 枚举所有面额的硬币
for i in range(1, amount + 1):
# 对于每个目标金额,枚举所有面额的硬币
for coin in coins:
# 如果当前硬币面额小于目标金额
if coin <= i:
# 更新动态规划表
dp[i] = min(dp[i], dp[i - coin] + 1)
# 返回凑成目标金额的最少硬币数
return dp[amount] if dp[amount] != float('inf') else -1
实例解析:拨开迷雾,洞悉玄机
假设我们有硬币面额为 [1, 2, 5],目标金额为 11。
- 对于目标金额为 1,显然需要 1 枚 1 元硬币,dp[1] = 1。
- 对于目标金额为 2,可以选择 1 枚 2 元硬币或 2 枚 1 元硬币,dp[2] = min(dp[2 - 2] + 1, dp[2 - 1] + 1) = 1。
- 对于目标金额为 3,可以选择 1 枚 2 元硬币和 1 枚 1 元硬币,dp[3] = dp[3 - 2] + 1 = 2。
- 对于目标金额为 4,可以选择 2 枚 2 元硬币或 4 枚 1 元硬币,dp[4] = min(dp[4 - 2] + 1, dp[4 - 1] + 1) = 2。
- 以此类推,我们不断更新动态规划表,最终得到 dp[11] = 3,表明凑成 11 元的最少硬币数为 3,分别为 1 枚 5 元硬币、1 枚 2 元硬币和 1 枚 1 元硬币。
总结反思:登高望远,弦歌不辍
算法求解,是一场智慧的较量,更是一次心灵的淬炼。通过对 LeetCode 322 题零钱兑换的深入探索,我们领悟到贪心与动态规划的精妙,体会到分解问题与逐步求解的奥秘。
在刷题征途上,我们永不停歇,披荆斩棘,向算法巅峰不断攀登。每一次解题,都是对思维的淬炼,每一份代码,都是智慧的结晶。让我们携手共进,在算法的海洋中乘风破浪,开辟属于我们的算法传奇!