leetcode 322 零钱兑换

题目描述:

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

示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3 
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1

思路1:

暴力递归:

从第一个coin开始,依次计算使用coin个数从0到n的结果

basecase为当coin遍历过最后一个的时候,amount是否为0

变量为index,amount

代码1:(超时了)

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        res = self.process(0, coins, amount)
        if res == float('inf'):
            return -1
        else:
            return res
    def process(self, index, coins, amount):
        if index == len(coins):
            if amount == 0:
                return 0
            else:
                return -1
        res = float('inf')
        count = 0
        while count * coins[index] <= amount:
            cur = self.process(index+1, coins, amount-count*coins[index])
            if cur == -1:
                count += 1
                continue
            else:
                res = min(res, cur + count)
                count += 1
        return res

思路2:

递归思路2:

coins=[1,2,5]时,f(amount) = min(f(amount -1), f(amount-2), f(amount-5)) + 1

动态规划思路2:

从头开始到amount,计算每个数值的最小个数

代码2:

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        max_v = float('inf')
        dp = [0] + [max_v] * amount
        for i in range(1, amount + 1):
            dp[i] = min(dp[i - c] if i - c >= 0 else max_v for c in coins) + 1
        return dp[-1] if dp[-1] != max_v else -1

思路3:

import math

class Solution:
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        coins.sort(reverse=True)
        # 硬币总个数
        result = amount + 1
        max_length = len(coins) - 1

        def update(index, target, count):
            nonlocal result
            if count + math.ceil(target / coins[index]) >= result:
                return

            if target % coins[index] == 0:
                result = count + target // coins[index]

            if index == max_length:
                return

            # 从多到少依次尝试取出当前币值的硬币
            for coin_num in range(target // coins[index], -1, -1):
                update(index + 1, target - coins[index] * coin_num, count + coin_num)

        update(0, amount, 0)
        return -1 if result == amount + 1 else result

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值