【力扣日记】322 零钱兑换 | 动态规划

题目描述

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

你可以认为每种硬币的数量是无限的。

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

算法思路

动态规划

自底向上

这里第一个想到的是自底向上动态规划

动态转移方程:dp[i]=dp[i-coin]+1;coin是一个列表

        # dp[i] 表示金额为i需要最少的硬币
        # dp[i] = min(dp[i], dp[i - coins[j]]) j所有硬币

算法:
第一步:dp数组初始化

        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

执行用时 :1084 ms, 在所有 Python3 提交中击败了90.63%的用户
内存消耗 :13.6 MB, 在所有 Python3 提交中击败了22.01%的用户

自顶向下

递归的动态规划

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

——
解释:

        import functools
        @functools.lru_cache(None)

@functools.lru_cache(maxsize=128, typed=False)
一个为函数提供缓存功能的装饰器,缓存 maxsize 组传入参数,在下次以相同参数调用时直接返回上一次的结果。

扫描二维码关注公众号,回复: 9876173 查看本文章

广度优先搜索 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

每一次都是遍历所有的硬币可能,然后硬币数量加一,当tmp==0;return step即是最少硬币数

深度优先搜索 DFS

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        coins.sort(reverse=True)
        self.res = float("inf")
        
        def dfs(i, num, amount):
            if amount == 0:
                self.res = min(self.res, num)
                return 
            for j in range(i, len(coins)):
                # 剩下的最大值都不够凑出来了
                if (self.res - num) * coins[j] < amount:
                    break
                if coins[j] > amount:
                    continue
                dfs(j, num + 1, amount - coins[j])
                
        for i in range(len(coins)):
            dfs(i, 0, amount)
            
        return self.res if self.res != float("inf") else -1

作者:powcai
链接:https://leetcode-cn.com/problems/coin-change/solution/dong-tai-gui-hua-bfs-dfs-by-powcai/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

来源

powcai

发布了210 篇原创文章 · 获赞 20 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Heart_for_Ling/article/details/104730953