給定不同面額的硬幣 coins 和一個總金額 amount。編寫一個函數來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 -1。
示例 1:
輸入: coins = [1, 2, 5], amount = 11
輸出: 3
解釋: 11 = 5 + 5 + 1
示例 2:
輸入: coins = [2], amount = 3
輸出: -1
說明:你可以認爲每種硬幣的數量是無限的。
題目連接:https://leetcode-cn.com/problems/coin-change/
方法一:遞歸實現
思路:見到可以將大問題劃分爲更小規模的問題,那麼就可以想到用動態規劃的方法。就像這道題,首先我們知道amount規模的問題,可以變成amount-coins[i]規模的問題,那麼問題來了,amount規模的問題與amount-coins[i]規模的問題之間的關係是什麼,遞歸結束條件是什麼(也就是說已知的邊界值是什麼?)?然後將這個思路寫成遞歸方程和遞歸結束條件,之後將其轉換成代碼。由於遞歸會超時,所以要用字典保存計算的中間結果。
注意:如果amount-coins[i]<0時,不符合題意,所以需要判斷一下滿足amount>=coins[i]才能遞歸。
class Solution:
def coinC(self, amount):
if amount==0:
return 0
tt = float('Inf')
for i in range(len(self.coins)):
if amount>=self.coins[i]:
if self.amt[amount-self.coins[i]]==-1:
aa=1+self.coinC(amount-self.coins[i])
else:
aa = 1 + self.amt[amount - self.coins[i]]
tt = min(tt, aa)
self.amt[amount]=tt
return tt
def coinChange(self, coins, amount):
self.coins = coins
# self.tt = float('Inf')
self.amt = [-1 for i in range(amount+1)]
ans = self.coinC(amount)
if ans!=float('Inf'):
print(ans)
else:
print(-1)
coins = [1, 2, 5]
amount = 11
s = Solution()
s.coinChange(coins, amount)
方法二:動態規劃
思路:從前向後想,假設我有初始最優解,那麼,我怎麼求更大規模的最優解。就這一道題來說,當amount==0時,我最少需要找0個硬幣,那更大規模的呢?怎麼求解呢?如果是amount==1時,如果存在1元硬幣,那麼就返回1,否則,是無窮大,也就是沒辦法找;如果amount==2時,可以是因爲amount>1,所以可以是1+f(2-1)=1+1=2,如果存在兩元硬幣的話,就是1+f(2-2)=1+0=1,將這兩種方案比較,看哪個硬幣個數少就要哪個,最後計算到amount==題目中所給的金額,即爲所求。
dp[0]=0
dp[i]=1+min{dp[i-coins[j]]}(j=0, ..., len(coins)-1)
注意:這個也是隻有i>=coins[j]時才更新
class Solution:
def coinChange(self, coins, amount):
dp=[float('Inf') for i in range(amount+1)]
dp[0]=0
for i in range(1, amount+1):
tt = float('Inf')
for j in range(len(coins)):
if i>=coins[j]:
a = dp[i-coins[j]]
tt = min(tt, a)
dp[i]=tt+1
if dp[amount]==float('Inf'):
return -1
else:
return dp[amount]
動態規劃入門第一題,加油!!!