[LeetCode] #518. Coin Change 2

題目

You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.

Return the number of combinations that make up that amount. If that amount of money cannot be made up by any combination of the coins, return 0.

You may assume that you have an infinite number of each kind of coin.

The answer is guaranteed to fit into a signed 32-bit integer.

直覺解

構想:

70. Climbing Stairs 那樣,amount 對應到樓梯總共有幾階,coins 對應到不同的 step。

python 3 實作(失敗):

class Solution: 
    def change(self, amount: int, coins: List[int]) -> int:
        return self.coin_change(0, amount, coins)

    def coin_change(self, curr, amount, coins):
        if curr > amount:
            return 0
        if curr == amount:
            return 1
        result = []
        for coin in coins:
            result.append(self.coin_change(curr + coin, amount, coins))
        return sum(result)

執行結果:

Wrong Answer

Input:

5
[1, 2, 5]

Output: 9

Expected: 4

錯誤發生原因:

  • 題目不在乎兌換的順序。但我的寫法,相同的硬幣兌換數量,會因為兌換順序不同而被重複計算。例如,同樣都是「把 5 塊換成 2 個 2 塊和 1 個 1 塊」,但是兌換順序有好幾種,例如「1 + 2 + 2」、「2 + 1 + 2」、「2 + 2 + 1」。

構想:

兌換過程中,如果已經開始兌換面額比較小的硬幣,就不能再兌換面額大的硬幣。例如,總共有 1, 2, 5 三種面額的硬幣,如果一開始就兌換了一個面額 1 的硬幣,之後就只能兌換 面額 ≤ 1 的硬幣。這樣的話,「把 5 塊換成 2 個 2 塊和 1 個 1 塊」就只會有一種兌換順序「2 + 2 + 1」,就能避免重複計算的問題。

自己的 python 3 實作(失敗):

class Solution: 
    def change(self, amount: int, coins: List[int]) -> int:
        coins.sort(reverse=True)
        coin_num = {}
        for coin in coins:
            coin_num[coin] = 0

        return self.coin_change(0, coin_num, amount, coins)

    def coin_change(self, curr, coin_num, amount, coins):
        if curr > amount:
            return 0
        if curr == amount:
            return 1
        star = 0
        for coin, num in coin_num.items():
            if num != 0:
                star = coins.index(coin)


        result = []
        for index, coin in enumerate(coins[star:]):
            coin_num_update = coin_num.copy()
            coin_num_update[coin] += 1

            result.append(self.coin_change(curr + coin, coin_num_update, amount, coins))
        return sum(result)

執行結果:

Time Limit Exceeded

Last executed input:
500
[3,5,7,8,9,10,11]

構想:

加上快取機制,看能不能加快計算速度

自己的 python 3 實作(失敗):

class Solution: 
    def change(self, amount: int, coins: List[int]) -> int:
        coins.sort(reverse=True)
        cache = {}
        coin_num = {}
        for coin in coins:
            coin_num[coin] = 0
        return self.coin_change(0, coin_num, amount, coins, cache)

    def coin_change(self, curr, coin_num, amount, coins, cache):
        if curr > amount:
            return 0
        if curr == amount:
            return 1

        tag = '#'.join([str(item) for item in coin_num.values()])
        if cache.get(tag) is None:
            star = 0
            for coin, num in coin_num.items():
                if num != 0:
                   star = coins.index(coin)

            result = []
            for index, coin in enumerate(coins[star:]):
                coin_num_update = coin_num.copy()
                coin_num_update[coin] += 1
                result.append(self.coin_change(curr + coin, coin_num_update, amount, coins, cache))
            cache[tag] = sum(result)
        return cache[tag]

執行結果:

Time Limit Exceeded

Last executed input:
500
[3,5,7,8,9,10,11]

研究別人的解

來源:Python sol by DP in bottom-up 85%+ [w/ Visualization]

別人的 python 3 實作:

class Solution: 
    def change(self, amount: int, coins: List[int]) -> int:

        # base case:
        # amount 0's method count = 1 (by taking no coins)
        change_method_count = [1] + [ 0 for _ in range(amount)]

        # make change with current coin, from small coin to large coin
        for cur_coin in coins:

            # update change method count from small amount to large amount
            for small_amount in range(cur_coin, amount+1):


            nbsp;   # current small amount can make changed with current coin
            nbsp;   change_method_count[small_amount] += change_method_count[small_amount - cur_coin]
        return change_method_count[amount]

效能:

Runtime: 132 ms, faster than 95.97% of Python3 online submissions for Coin Change 2.
Memory Usage: 14.5 MB, less than 67.61% of Python3 online submissions for Coin Change 2.

Comments

Popular posts from this blog

Alpha Camp 全端開發課程學習心得

在 javascript 用 regular expression 為金額加上千位數分隔符號

shop_platform - sqlalchemy.exc.TimeoutError