今天面试问了个题目,有2元和3元的硬币无数个,组合成99元有多少种方式?
下面是我当时写的
# 99 2 3
# dp[j] = max{dp[j-2],dp[j-3]}
# dp[2] = 1 dp[3]=1 dp[1]=dp[0]= 0
def fun(total_amount):
dp = [0 for i in range(total_amount+1)]
dp[0] = 1
j = 2
while j < total_amount+1:
dp[j] = dp[j-2]+dp[j-3]
j+=1
return dp
ans = fun(total_amount=7)
print(ans)
答案当然是不对的,问题在哪呢?乍一看好像dp[j] = dp[j-2]+dp[j-3]没毛病。但是这里忽略了一个问题,就是硬币的组合不含顺序。
比如以 7 元为例子,应该有 2 2 3这一种组合,但是我上面的代码计算的其实是 2 2 3,2 3 2, 3 2 2三种组合。
因此正确的算法应该注意硬币的顺序,比如数值小的硬币要在数值大的硬币前面。怎么做呢?只需要两层循环,外面的循环从小到大遍历硬币,里面的循环遍历总钱数。
def count_combinations(total_amount):
coins = [2, 3] # 可用的硬币面额
dp = [0] * (total_amount + 1) # 动态规划数组,dp[i] 表示凑成金额 i 的组合数量
dp[0] = 1 # 初始化金额为 0 时的组合数量为 1
for coin in coins:
for i in range(coin, total_amount + 1):
dp[i] += dp[i - coin]
'''
这样就避免了硬币的顺序问题,
'''
return dp[total_amount]
total_combinations = count_combinations(10)
print(total_combinations)