代码随想录算法训练营Day32 | 518.零钱兑换II、377. 组合总和 Ⅳ、70. 爬楼梯(进阶)

LeetCode518.零钱兑换II

518. 零钱兑换 II - 力扣(LeetCode)

1.思路

动态规划五部曲:

  1. dpj:凑成金额 j 的货币组合数;

  2. 在求 目标和 的那道题中,求装满背包有几种方法,这里也是求总金额凑成 amount 的方法数,所以这里的递推公式为:dpj = dpj + dpj - coins\[i];

  3. dp0 = 1,不放任何物品,即装满背包容量为 0 的方法是 1;

  4. 这道题里的物品和前面 01 背包不同,这里是可以无限次使用的,所以遍历时的内层背包遍历需要从前往后遍历。外层依然遍历物品。此时求得是组合数;

假设:coins0 = 1,coins1 = 5。

那么就是先把1加入计算,然后再把5加入计算,得到的方法数量只有{1, 5}这种情况。而不会出现{5, 1}的情况。

如果外层遍历得是背包,内层遍历物品,那么求得就是排列数了,

背包容量的每一个值,都是经过 1 和 5 的计算,包含了{1, 5} 和 {5, 1}两种情况。

  1. amount = 5,coins = 1,2,5,dp:
cpp 复制代码
class Solution {
public:
    int change(int amount, vector<int>& coins) {
        vector<int>dp(amount+1,0);
        dp[0]=1;
        for(int i=0;i<coins.size();i++){
            for(int j=coins[i];j<=amount;j++){
                if(dp[j]<INT_MAX-dp[j-coins[i]]){
                    dp[j]=dp[j]+dp[j-coins[i]];
                }
            }
        }
        return dp[amount];
    }
};

2.复杂度分析

时间复杂度:O(m*n) - m 是 amount,n 是 coins 得长度

空间复杂度:O(m)

3.思考

这道题代码一写出来就是很简单,不过却很难思考。

如果求组合数就是外层for循环遍历物品,内层for遍历背包。

如果求排列数就是外层for遍历背包,内层for循环遍历物品。

如果物品只能用一次,内层 for 就反向遍历。

如果物品能重复使用,内层 for 就正向遍历。

4.Reference:518.零钱兑换II | 代码随想录


LeetCode377. 组合总和 Ⅳ

377. 组合总和 Ⅳ - 力扣(LeetCode)

1.思路

动态规划五部曲:

  1. dpi:凑成正整数 i 得排列个数;

  2. 这道题也是求装满背包得方法,所以递推公式:dpj = dj + dj - nums\[i];

  3. 因为递推公式 dpi += dpi - nums\[j] 的缘故,dp0要初始化为1,这样递归其他dpi的时候才会有数值基础。

  4. 本题求得是组合数,所以外层 for 循环遍历背包,内层 for 循环遍历物品;

如果把遍历 物品 放在外循环,遍历 target 作为内循环的话,举例:计算dp4的时候,结果集只有 {1,3} 这样的集合,不会有 {3,1} 这样的集合,因为 nums 遍历放在外层,3 只能出现在 1 后面;

  1. nums = 1,2,3,target = 4
cpp 复制代码
class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        vector<int>dp(target+1,0);
        dp[0]=1;
        for(int j=0;j<=target;j++){
            for(int i=0;i<nums.size();i++){
                if(j>=nums[i] && dp[j]<=INT_MAX-dp[j-nums[i]]) dp[j]=dp[j]+dp[j-nums[i]];
            }
        }
        return dp[target];
    }
};

注:C++测试用例有两个数相加超过int的数据,所以需要在if里加上dpi < INT_MAX - dpi - num

2.复杂度分析

时间复杂度:O(target*n)

空间复杂度:O(target)

3.Reference:377. 组合总和 Ⅳ | 代码随想录


LeetCode70.爬楼梯(进阶)

57. 爬楼梯(第八期模拟笔试)

1.思路

1阶,2阶,3阶,m阶是物品,楼顶 n 为背包。

动态规划五部曲:

  1. dpi:爬到楼顶为 i 个阶梯得方法数;

  2. 求装满背包有多少种方法的递推公式是:dpj = dpj + dpj - nums\[i],这里的阶梯数从 1 ~ m,dpi 的来源也是这些,所以递推公式:dpj = dpj + dpj - i

  3. dp0 = 1,dp0是递归中一切数值的基础所在,如果dp0是0的话,其他数值都是0了;

  4. 1、2 步 和 2、1 步都是上三个台阶,但是这两种方法不一样,所以这里求的是排列数,所以外层循环背包,内层循环物品;

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main(){
    int n,m;
    while(cin>>n>>m){
        vector<int>dp(n+1,0);
        dp[0]=1;
        for(int j=1;j<=n;j++){
            for(int i=1;i<=m;i++){
                if(j>=i){
                    dp[j]=dp[j]+dp[j-i];
                }
            }
        }
        cout<<dp[n];
    }
    return 0;
}

2.复杂度分析

时间复杂度:O(n*m)

空间复杂度:O(n)

3.思考

还是明白最重要的一点,求组合就是先物品后背包,求排列就是先背包后物品。

4.Reference:70. 爬楼梯(进阶版) | 代码随想录

相关推荐
青山木几秒前
Hot 100 --- 岛屿数量
java·数据结构·算法·leetcode·深度优先·广度优先
不会就选b16 分钟前
算法日常・每日刷题--<归并排序>1
数据结构·算法
啦啦啦啦啦zzzz42 分钟前
算法:回溯算法
c++·算法·leetcode
IT探索1 小时前
Linux 查找文件指令总结
linux·算法
Lumos1862 小时前
51单片机从零到实战(完结)——后续学习路线建议
算法
稚南城才子,乌衣巷风流2 小时前
DFS序详解:原理、应用与实现
算法·深度优先·图论
稚南城才子,乌衣巷风流2 小时前
动态树(Dynamic Tree)数据结构详解
数据结构·算法
变量未定义~3 小时前
最小生成树1(Prim模板)、最小生成树2(kruskal模板)、最近公共祖先(模板)
算法
这就是佬们吗3 小时前
Python入门⑤-异常处理、文件操作与实战项目
开发语言·数据库·python·算法·pycharm