代码随想录算法训练营第四十三天|518. 零钱兑换II、377. 组合总和 IV

LeetCode 518. 零钱兑换II
题目链接:518. 零钱兑换 II - 力扣(LeetCode)代码随想录算法训练营第四十三天|518. 零钱兑换II、377. 组合总和 IV_第1张图片

完全背包问题开始,对于某一个面值的硬币可以无限使用,因此,我们在二维数组的内循环正向遍历,这样其实就OK了

每道题都要考虑dp五步:

1)确定dp数组下标与值的关系:满足凑出总金额的组合数

2)确定递推公式:我们把n个数组成看作1与n-1个组成,使用分而治之的思路来处理,dp[i] += dp[i - coin]

3)确定初始值:dp[0]为1,没得选

4)确定遍历的数:注意一下边界问题

5)带入验证一下

代码:

#python
from typing import List  
  
class Solution:  
    def change(self, amount: int, coins: List[int]) -> int:  
        dp = [0] * (amount + 1)  //dp到target这个位置就好
        dp[0] = 1  //注意初始值别选错了
        for coin in coins:  
            for j in range(coin, amount + 1):  
                dp[j] += dp[j - coin]  //就是刚刚提到的递推公式的确定
  
        return dp[-1] //返回最后一个,就是在target位置的最多组合数量

LeetCode 377. 组合总和 IV
题目链接:377. 组合总和 Ⅳ - 力扣(LeetCode)代码随想录算法训练营第四十三天|518. 零钱兑换II、377. 组合总和 IV_第2张图片

这道题就很离谱了,其实考虑的是排列,也就是相同元素可能会算很多次。

代码随想录算法训练营第四十三天|518. 零钱兑换II、377. 组合总和 IV_第3张图片

因此对于该题,我们考虑一下,和上面那道题分而治之挺像的,永远关注与当前的选择,当前能选的全部选进去。所以循环我们从值开始做外循环,随后用num来做内循环,只要还放得进去我们就放呗。

每道题都要考虑dp五步:

1)确定dp数组下标与值的关系:满足凑出的组合数

2)确定递推公式:我们把n个数组成看作1与n-1个组成,使用分而治之的思路来处理,dp[i] += dp[i - num]

3)确定初始值:dp[0]为1,没得选

4)确定遍历的数:注意一下边界问题

5)带入验证一下

代码:

#python
class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        dp = [0 for _ in range(target + 1)]
        dp[0] = 1 //注意初始值选择为1
        for i in range(target + 1):
            for num in nums:
                if i - num >= 0:  //因为和之前的先遍历物品,再遍历背包容量不同,我们内外循环反过来了,因此需要额外进行判别,小心别dp数组过界了
                    dp[i] += dp[i - num]  //和上一题是一样的
        return dp[-1]  //返回最后一个结果

你可能感兴趣的:(算法)