leetcode【中等】零钱兑换2【中等】

给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
在这里插入图片描述
思路1:递归
类似问题: 39、组合总和【中等】
不同之处:超时了
在这里插入图片描述

def change( amount, coins) :
    def dfs(begin,target):
        if target<0:
            return
        if target==0:
            res[0]+=1
            return
        for i in range(begin,len(coins)):
            resuid=target-coins[i]
            dfs(i,resuid)
    dfs(0,amount)
    return res[0]

思路2:动态规划 / 背包问题
类似问题:70、爬楼梯【简单】

  • 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

不同之处:爬楼梯是【排列】问题,零钱兑换是【组合】问题

爬楼梯:DP[i] = DP[i-1] = DP[i-2]

背包问题:

  • 填满容量为j的背包,有dp[j]种方法
  • 填满容量为j - nums[i]的背包,有dp[j - nums[i]]种方法。
  • 已经有了nums[i] = 2,那么填满一个容量为5的背包,有dp[3]种方法

递推公式:
遍历nums[i],把所有的dp[j - nums[i]]累加起来:
dp[j] =dp[j]+ dp[j - nums[i]]

class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        dp=[0 for _ in range(amount+1)]#多一位
        dp[0]=1#没有硬币
        for coin in coins:
        	#coin进来以后,比coin小的数的组合肯定不会变啦
            for i in range(coin,amount+1):
                dp[i]+=dp[i-coin]
        return dp[amount]#dp里的第六个数即dp[5]

注意!不能写成:

for i in range(1,amount+1):
    for coin in coins:
        dp[i]+=dp[i-coin]
  • 外层 coin 循环实际上是表示每次有新的 coin 参与进来,dp[x] 的值就会更新,最后直到所有的 硬币都参与选择的时候 dp[x]才有定值 ;
  • 内层循环是总金额 dp[x]在内层循环里面不停的在更新。主要是求组合数,coin 必须写在外面去重,不然写在内层循环的话是求排列数
  • 所以要全部使用完一种硬币,保证后面不会再用到

猜你喜欢

转载自blog.csdn.net/qq_40707462/article/details/114273487