返回
勇闯 LeetCode,硬币消消乐,妙招频出,尽在掌握
闲谈
2024-01-18 14:24:35
序言
踏上算法竞赛的征途,LeetCode 是一座无法绕过的丰碑。其中一道经典题目——“拿硬币”,考验着算法爱好者的思维和策略。本文将深入剖析这道题目的巧妙解法,带你领略动态规划算法的强大魅力。
题目解析
“拿硬币”题目如下:
桌上摆放着 n 堆力扣币,每堆中硬币的数量分别存储在数组 coins 中。你每次可以执行以下两种操作之一:
- 拿走当前堆中一枚硬币
- 拿走当前堆中两枚硬币
你的目标是拿走所有硬币,并使拿取次数尽可能少。求出最少需要的拿取次数。
动态规划算法
解决这道题目,我们可以运用动态规划算法。动态规划算法是一种自底向上、逐步求解问题的技术,适用于具有“最优子结构”特征的问题。
在“拿硬币”问题中,我们可以定义状态 dp[i] 为拿完前 i 堆硬币所需的最小拿取次数。为了获得最优解,我们需要依次计算出 dp[1]、dp[2]、...、dp[n]。
状态转移方程
在计算 dp[i] 时,我们需要考虑两种情况:
- 如果从第 i 堆硬币中拿走一枚硬币,则 dp[i] = dp[i-1] + 1
- 如果从第 i 堆硬币中拿走两枚硬币,则 dp[i] = dp[i-2] + 1
具体步骤
根据状态转移方程,我们可以得到以下具体步骤:
- 初始化: dp[0] = 0,dp[1] = 1
- 循环递推: 对于 i 从 2 循环到 n,计算 dp[i]
- 如果 coins[i-1] >= 2,则 dp[i] = min(dp[i-1] + 1, dp[i-2] + 1)
- 否则,dp[i] = dp[i-1] + 1
- 返回结果: 返回 dp[n]
时间复杂度
该算法的时间复杂度为 O(n),其中 n 为硬币堆数。
代码示例(Python)
def minCount(coins):
dp = [0] * (len(coins) + 1)
dp[1] = 1
for i in range(2, len(coins) + 1):
if coins[i-1] >= 2:
dp[i] = min(dp[i-1] + 1, dp[i-2] + 1)
else:
dp[i] = dp[i-1] + 1
return dp[len(coins)]
总结
“拿硬币”问题看似简单,但蕴藏着动态规划算法的精妙之处。通过将问题分解成子问题,并逐一求解,我们能够高效地找到最优解。掌握动态规划算法,不仅能够解决竞赛中的难题,更能提升我们对算法设计和问题的抽象能力。