力扣322.零錢兌換

給定不同面額的硬幣 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]規模的問題之間的關係是什麼,遞歸結束條件是什麼(也就是說已知的邊界值是什麼?)?然後將這個思路寫成遞歸方程和遞歸結束條件,之後將其轉換成代碼。由於遞歸會超時,所以要用字典保存計算的中間結果。

$$ f(amount)=\left\{ \begin{aligned} 0, amount = 0 \\ 1+min{f(amount-coins[i])]}(i=0, 1,...,len(coins)-1), amount != 0 \end{aligned} \right. $$

注意:如果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]

動態規劃入門第一題,加油!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章