代码随想录算法训练营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. 爬楼梯(进阶版) | 代码随想录

相关推荐
先吃饱再说3 小时前
判断回文字符串,从一行代码到双指针优化
算法
黄敬峰6 小时前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术7 小时前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六11 小时前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术11 小时前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
Asize12 小时前
初识DFS 与 BFS:递归、队列与图遍历
算法
罗西的思考1 天前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习
美团技术团队1 天前
LongCat 开源 VitaBench 2.0:长期动态智能体基准新标杆
人工智能·算法
To_OC2 天前
LC 207 课程表:刚学图论那会儿,我连这是拓扑排序都没看出来
javascript·算法·leetcode