零钱兑换

作者: _阿南_ | 来源:发表于2020-03-09 20:56 被阅读0次

    题目:

    给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
    示例 1:
    输入: coins = [1, 2, 5], amount = 11
    输出: 3 
    解释: 11 = 5 + 5 + 1
    示例 2:
    输入: coins = [2], amount = 3
    输出: -1
    说明:
    你可以认为每种硬币的数量是无限的。
    

    题目的理解:

    看似很简单的题目,用了一天时间编写算法,但是结果是一直计算超时,!_!
    参考了其他的解题思路,学习学习!

    python实现

    深度遍历(dfs):
    class Solution:
        def coinChange(self, coins: List[int], amount: int) -> int:
            coins.sort(reverse=True)
            self.result = float('inf')
    
            def recycle(i, num, balance):
                if balance == 0:
                    self.result = min(self.result, num)
                    return
    
                for j in range(i, len(coins)):
                    if (self.result - num) * coins[j] < balance:
                        break
                    
                    if balance < coins[j]:
                        continue
    
                    recycle(j, num + 1, balance - coins[j])
    
            for i in range(len(coins)):
                recycle(i, 0, amount)
    
            return self.result if self.result != float('inf') else -1
    

    思路是(1)将硬币从大到小排序 (2)依次进行堆放硬币,当达到指定值停止。(3)堆放过程中记录使用硬币的次数。(4)取出使用硬币最少的次数。(5)需要通过判断循环遍历是否有可能超过最小硬币数,来达到提高效率的方式。

    广度遍历(bfs):
    class Solution:
        def coinChange(self, coins: List[int], amount: int) -> int:
            from collections import deque
            queue = deque([amount])
            step = 0
            visited = set()
            while queue:
                n = len(queue)
                for _ in range(n):
                    tmp = queue.pop()
                    if tmp == 0:
                        return step
                    for coin in coins:
                        if tmp >= coin and tmp - coin not in visited:
                            visited.add(tmp - coin)
                            queue.appendleft(tmp - coin)
                step += 1
            return -1
    

    思路:(1)目标金额进行每个硬币的计算。 (2)所有的值计算一次后得到一个层级的所有数。(3)继续计算下一层的数。(4)直到出现第一个0时,计算结束。

    动态规划
    1. 自底向上
    class Solution:
        def coinChange(self, coins: List[int], amount: int) -> int:
            # 自底向上
            # dp[i] 表示金额为i需要最少的硬币
            # dp[i] = min(dp[i], dp[i - coins[j]]) j所有硬币
            
            dp = [float("inf")] * (amount + 1)
            dp[0] = 0
            for i in range(1, amount + 1):
                dp[i] = min(dp[i - c] if i - c >= 0 else float("inf") for c in coins ) + 1
            return dp[-1] if dp[-1] != float("inf") else -1
    

    思路:(1)根据提供的硬币,来计算1到amount每一个数需要的硬币个数。(2)amount数值大时,减去每一个硬币后转化为小数值来得到硬币个数。(3)减去的硬币数值就算使用了一个硬币。

    1. 自顶向下
    class Solution:
        def coinChange(self, coins: List[int], amount: int) -> int:
            import functools
            @functools.lru_cache(None)
            def helper(amount):
                if amount == 0:
                    return 0
                return min(helper(amount - c) if amount - c >= 0 else float("inf") for c in coins) + 1
            res = helper(amount)
            return res if res != float("inf") else -1
    

    思路:(1)计算amount减去一个硬币后的值X,来获取X的硬币数。(2)一直递归返回值。

    提交

    好算法,还是不错的。

    // END 多读书多写代码

    相关文章

      网友评论

        本文标题:零钱兑换

        本文链接:https://www.haomeiwen.com/subject/kjrudhtx.html