【代码随想录】【算法训练营】【第43天】 [518]零钱兑换II [377]组合总和IV [卡码57]爬楼梯

news2024/11/17 11:40:51

前言

思路及算法思维,指路 代码随想录。
题目来自 LeetCode。
部分题目来自卡码网。

day 43,极其困难的周三~

题目详情

[518] 零钱兑换II

题目描述

518 零钱兑换II
518 零钱兑换II

解题思路

前提:假设每一种面额的硬币有无限个,求组合数
思路:完全背包问题,求组合数,dp[i][j]: 在[0, i]中取硬币凑成总金额为j的组合数,dp[i][j] = dp[i-1][j] + dp[i][j-coins[i]],使用一维数组即为dp[j] = dp[j] + dp[j-coins[i]]。
重点:组合数的遍历顺序:先遍历物品,后遍历背包。

代码实现

C语言
dp[i][j]
// 完全背包问题, 求组合数
// dp[i][j]: 在[0, i]中取硬币凑成总金额为j的组合数
// dp[i][j] = dp[i-1][j] + dp[i][j-coins[i]]

int change(int amount, int* coins, int coinsSize) {
    int dp[coinsSize][amount + 1];
    // dp数组初始化
    dp[0][0] = 1;
    for (int j = 1; j <= amount; j++) {
        if (j < coins[0]) {
            dp[0][j] = 0;
        } else {
            dp[0][j] = dp[0][j - coins[0]];
        }
    }
    // 组合数:先遍历硬币,再遍历总金额
    for (int i = 1; i < coinsSize; i++) {
        for (int j = 0; j <= amount; j++) {
            dp[i][j] = dp[i - 1][j];
            if (j >= coins[i]) {
                dp[i][j] += dp[i][j - coins[i]];
            }
        }
    }
    return dp[coinsSize - 1][amount];
}
dp[j]
// 完全背包问题, 求组合数
// 压缩dp[i][j]为dp[j]: 在[0, i]中取硬币凑成总金额为j的组合数
// dp[j] = dp[j] + dp[j-coins[i]]

int change(int amount, int* coins, int coinsSize) {
    int dp[amount + 1];
    // dp数组初始化
    dp[0] = 1;
    for (int j = 1; j <= amount; j++) {
        dp[j] = 0;
    }
    // 组合数:先遍历硬币,再遍历总金额
    for (int i = 0; i < coinsSize; i++) {
        for (int j = coins[i]; j <= amount; j++) {
            if (j >= coins[i]) {
                dp[j] += dp[j - coins[i]];
            }
        }
    }
    return dp[amount];
}

[377] 组合总和IV

题目描述

377 组合总和IV
377 组合总和IV

解题思路

前提:数组元素不同,顺序不同的序列被视作不同的组合。
思路:完全背包问题,求排列数,dp[i][j]: 从数组nums的前i个位置中取元素,和为j的组合数,dp[i][j] = dp[i-1][j] + dp[numsSize][j-nums[i]];压缩一维数组为dp[j] = dp[j] + dp[j-nums[i]]
重点:遍历顺序,二维数组的推导公式,以及初始化; dp[numsSize][j - nums[i]]可以理解为最后一位为nums[i]的排列数。

代码实现

C语言
dp[i][j]

dp[i][j]: 从数组nums的前i个位置中取元素,和为j的组合数,所以dp数组大小为int dp[numsSize + 1][target + 1],返回为dp[numsSize][target],dp[i][j] = dp[i-1][j] + dp[numsSize][j-nums[i]]

// 完全背包, 排列个数
// dp[i][j]: 从数组nums的前i个位置中取元素,和为j的组合数
// dp[i][j] = dp[i-1][j] + dp[numsSize][j-nums[i]]

int combinationSum4(int* nums, int numsSize, int target) {
    int dp[numsSize + 1][target + 1];
    // dp数组初始化
    for (int i = 0; i <= numsSize; i++) {
        // 首列
        dp[i][0] = 1;
    }
    for (int j = 1; j <= target; j++) {
        // 首行
        dp[0][j] = 0;
    }
    // 遍历, 排列数, 先遍历目标和target, 后遍历数组nums
    for (int j = 0; j <= target; j++) {
        for (int i = 1; i <= numsSize; i++) {
            dp[i][j] = dp[i - 1][j];
            if ((j >= nums[i - 1]) && (dp[i - 1][j] < INT_MAX - dp[numsSize][j - nums[i - 1]])) {
                dp[i][j] += dp[numsSize][j - nums[i - 1]];
            }
        }
    }
    return dp[numsSize][target];
}

dp[i][j]: 从数组nums的前i中取元素,和为j的组合数,所以dp数组大小为int dp[numsSize][target + 1],返回为dp[numsSize - 1][target],
dp[i][j] = dp[i-1][j] + dp[numsSize - 1][j-nums[i]]

// 完全背包, 排列个数
// dp[i][j]: 从数组nums的前i中取元素,和为j的组合数
// dp[i][j] = dp[i-1][j] + dp[numsSize - 1][j-nums[i]]
// dp[numsSize - 1][j - nums[i]]可以理解为最后一位为nums[i]的排列数

int combinationSum4(int* nums, int numsSize, int target) {
    int dp[numsSize][target + 1];
    // dp数组初始化
    dp[0][0] = 1;
    for (int i = 0; i < numsSize; i++) {
        dp[i][0] = 1;
    }
    // 遍历, 排列数, 先遍历目标和target, 后遍历数组nums
    for (int j = 1; j <= target; j++) {
        for (int i = 0; i < numsSize; i++) {
            if (i == 0) {
                dp[i][j] = 0;
            } else {
                dp[i][j] = dp[i - 1][j];
            }
            if ((j >= nums[i]) && (dp[i][j] < INT_MAX - dp[numsSize - 1][j - nums[i]])) {
                dp[i][j] += dp[numsSize - 1][j - nums[i]];
            }
        }
    }
    return dp[numsSize - 1][target];
}
dp[j]
// 完全背包, 排列个数
// dp[j]: 从数组nums的前i中取元素,和为j的排列数
// dp[j] = dp[j] + dp[j-nums[i]]

int combinationSum4(int* nums, int numsSize, int target) {
    int dp[target + 1];
    // dp数组初始化
    dp[0] = 1;
    for (int j = 1; j <= target; j++) {
        dp[j] = 0;
    }
    // 遍历, 排列数, 先遍历目标和target, 后遍历数组nums
    for (int j = 0; j <= target; j++) {
        for (int i = 0; i < numsSize; i++) {
            if ((j >= nums[i]) && (dp[j] < INT_MAX - dp[j - nums[i]])) {
                dp[j] += dp[j - nums[i]];
            }
        }
    }
    return dp[target];
}

[卡码57] 爬楼梯

题目描述

卡码57 爬楼梯
卡码57 爬楼梯

解题思路

前提:求到达楼顶的不同方法的数量
思路:完全背包,求排列数,dp[i][j]: 至多每次i个台阶,可以到达j阶高度的排列方法数, dp[i][j] = dp[i-1][j] + dp[m][j-i];压缩一维数组为dp[[j] = dp[j] + dp[j-i]
重点:遍历顺序,二维数组的推导公式,以及初始化。

代码实现

C语言
dp[i][j]
#include <stdio.h>
#include <stdlib.h>
 
// 完全背包,求排列数
// dp[i][j]: 至多每次i个台阶,可以到达j阶高度的排列方法数
// dp[i][j] = dp[i-1][j] + dp[m][j-i]
 
int clamb(int n, int m)
{
    int dp[m + 1][n + 1];
    // 初始化dp数组
    for (int i = 0; i <= m; i++) {
        // 首行
        dp[i][0] = 1;
    }
    for (int j = 1; j <= n; j++) {
        // 首列
        dp[0][j] = 0;
    }
    // 排列数,先遍历高度,再遍历每次台阶数
    for (int j = 1; j <= n; j++) {
        for (int i = 1; i <= m; i++) {
            dp[i][j] = dp[i - 1][j];
            if (j >= i) {
                dp[i][j] += dp[m][j - i];
            }
            //printf("%d %d %d\n", i, j, dp[i][j]);
        }
    }
    return dp[m][n];
}
 
int main()
{
    int n;
    int m;
    scanf("%d %d",&n, &m);
    int ans = clamb(n, m);
    printf("%d", ans);
    return 0;
}
dp[j]
#include <stdio.h>
#include <stdlib.h>
 
// 完全背包,求排列数
// dp[j]: 至多每次i个台阶,可以到达j阶高度的排列方法数
// dp[[j] = dp[j] + dp[j-i]
 
int clamb(int n, int m)
{
    int dp[n + 1];
    // 初始化dp数组
    dp[0] = 1;
    for (int j = 1; j <= n; j++) {
        dp[j] = 0;
    }
    // 排列数,先遍历高度,再遍历每次台阶数
    for (int j = 1; j <= n; j++) {
        for (int i = 1; i <= m; i++) {
            if (j >= i) {
                dp[j] += dp[j - i];
            }
            //printf("%d %d %d\n", i, j, dp[j]);
        }
    }
    return dp[n];
}
 
int main()
{
    int n;
    int m;
    scanf("%d %d",&n, &m);
    int ans = clamb(n, m);
    printf("%d", ans);
    return 0;
}

今日收获

  1. 完全背包问题:组合数(先遍历物品,后遍历背包),排列数(先遍历背包,后遍历物品);虽然一维dp数组的递推公式都是一样的,但是二维dp数组的递推公式有较大的差别,初始化也不太一样,排列数的 dp[i][j] = dp[i-1][j] + dp[numsSize - 1][j-nums[i]] 明显更难以理解一些。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1839211.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LVGL开发教程-Label文本

系列文章目录 知不足而奋进 望远山而前行 目录 系列文章目录 文章目录 前言 ​编辑 1. 文本显示 2. 使用字体 总结 前言 在嵌入式系统开发中&#xff0c;文本显示是一项基本而重要的功能。使用 LittlevGL&#xff08;LVGL&#xff09;库&#xff0c;我们可以轻松地创建…

华润的超市卡有什么用?

现在都很少有人会直接去超市买东西了&#xff0c;一般都是网购或者叫外卖啥的 最近我朋友送了张华润的礼品卡&#xff0c;但是感觉也没什么要买的 一边担心卡过期&#xff0c;一边发愁买什么 还好发现了收卡云啊&#xff0c;最后把卡在收卡云上卖掉了&#xff0c;到账速度贼…

org.springframework.boot:spring-boot-starter-parent:pom:2.3.4.RELEAS

前言 git上拉了一个项目构建过程中无论是clean还是install都报错 注&#xff1a;很看不惯某博主一点简单的经验分享都要开VIP才能查看的作风 org.springframework.boot:spring-boot-starter-parent:pom:2.3.4.RELEASE failed to transfer from https://maven.aliyun.com/rep…

免费的ai创作软件,各维度的盘点一下!

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到我们生活的方方面面&#xff0c;其中就包括内容创作领域。近年来&#xff0c;越来越多的免费AI创作软件涌现出来&#xff0c;为广大创作者提供了全新的创作方式和工具。那么&#xff0c;这些软件究…

C语言——扫雷小游戏

扫雷小游戏&#xff1a; 游戏最终效果&#xff1a; 1.先写一下游戏开始的简单界面。 用一个函数来写一下 void menu() {printf(" ---------------------------- \n");printf("| 1.play |\n");printf("| 0.exit …

工业 web4.0,UI 风格令人赞叹

工业 web4.0&#xff0c;UI 风格令人赞叹

揭秘后勤报修管理系统:目的明确,功能设计模块助您轻松管理

在数字化、信息化飞速发展的今天&#xff0c;企业后勤报修也迎来了前所未有的变革。传统的报修方式&#xff0c;如电话报修、纸质报修单等&#xff0c;已逐渐无法满足现代企事业单位对高效、便捷、精准报修服务的需求。因此&#xff0c;后勤报修管理系统应运而生&#xff0c;后…

ThinkPHP5大学生社会实践管理系统

有需要请加文章底部Q哦 可远程调试 ThinkPHP5大学生社会实践管理系统 一 介绍 大学生社会实践管理系统基于ThinkPHP5框架开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈&#xff1a;ThinkPHP5mysqlbootstrapphpstudyvscode 二 功…

Upload-Labs:Pass - 1(JS前端白名单)

Pass_1 1. 上传测试2. 代码审计**获取文件输入的值**&#xff1a;**检查是否选择了文件**&#xff1a;**定义允许的文件类型**&#xff1a;**提取文件的扩展名**&#xff1a;**检查文件类型是否允许上传**&#xff1a;**构建错误消息并提醒用户**&#xff1a; 3.绕过思路3.1 将…

2024-06-19,面试官问的问题

文章目录 1、采用minIO完成了图片存储&#xff0c;采用阿里云OSS服务器存储图片这两个功能面试官理解为重复&#xff0c;面试官又问minIO怎么同步到OSS&#xff1f;2、讲一下ThreadLocal&#xff1f;3、为什么用ThreadLocal存数据&#xff1f;4、redis有几种数据结构&#xff1…

18V-120V降12V300m恒压WT5117

18V-120V降12V300m恒压WT5117 WT5117 是一款专为开关电源设计的集成了 150V 高电压 MOSFET 的 DC-DC 控制器。这个设备具备内置高压启动和自供电功能&#xff0c;能够满足快速启动及低能耗待机状态的需求。 WT5117 配备了自适应降频技术&#xff0c;以提升在低负载条件下的转换…

构建高效、便捷的家校沟通桥梁

在现代教育中&#xff0c;家校之间的有效沟通和协作是确保学生全面发展的关键。搭贝家校管理应用通过一系列强大而便捷的功能&#xff0c;帮助学校和家长实现无缝对接&#xff0c;提供全面的管理和服务。以下是搭贝家校管理应用的主要功能和优势。 &#x1f3eb; 主要功能模…

资源宝库网站!人人必备的神器!

面对网络中海量的内容&#xff0c;一个高效、便捷的网络导航工具&#xff0c;可以帮助我们快速查找使用网络资源。无论是职场精英还是学生党&#xff0c;使用导航网站都可以帮助我们提升效率。下面小编就来和大家分享一款资源宝库网站-办公人导航-实用的办公生活导航网站&#…

docker-compose设置永久启动、自动重启

步骤一 找到 docker-compose.yml 文件 步骤二 vim 打开文件 找到 image: PS&#xff1a;就是为了对齐格式 步骤三 在其下方添加&#xff1a; restart: always而后保存即可

Apple Watch设计原则,让你开发app思路更清晰

Apple Watch 作为一款极具前瞻性的产品&#xff0c;硬件已经发展到 Apple Watch Series 6。智能手表是目前除了手机之外&#xff0c; 最方便人眼观看且较为成熟的商业化硬件。这次加速器活动带给我的触动很大&#xff0c;原以为 Apple Watch 只是一款小众产品&#xff0c;实际上…

在 Visual Studio 2022 中使用命令删除 GitHub 的本地分支可以通过以下步骤完成

打开终端窗口: 在 Visual Studio 2022 中&#xff0c;打开你的项目或者代码库。 打开 “View” 菜单&#xff0c;然后选择 “Terminal” 打开终端窗口。 查看当前分支: 在终端窗口中输入以下命令&#xff0c;查看当前的本地分支列表&#xff1a; 复制代码 git branch 这会列出…

防爆气象站:化工厂区气象环境监测的最佳选择

在化工厂区&#xff0c;气象环境监测至关重要&#xff0c;它直接关系到生产安全、环境保护以及员工健康。防爆气象站作为专业的监测设备&#xff0c;凭借其独特的防爆性能和精准的数据监测能力&#xff0c;成为化工厂区气象环境监测的最佳选择。 防爆气象站采用先进的防爆技术…

CityEngine记录1:工程目录

CityEngine的工程目录结构对于理解和组织3D城市建模项目至关重要。以下是对CityEngine工程目录结构的详细解析&#xff1a; Assets&#xff1a; 存放模型的零件与纹理图片。这些资产通常用于在建模过程中为建筑物、道路、植被等元素添加详细的纹理和细节。 Data&#xff1a; …

Linux内核编程(六)平台总线plantform驱动模型

本文目录 前述&#xff1a;为什么引入平台总线模型一、知识点1. 什么是平台总线模型2. 平台总线模型使用3. 平台总线是如何工作的4. 平台总线模型的优点 二、平台总线设备层1. 常用API&#xff08;1&#xff09; 注册一个平台设备&#xff08;2&#xff09; 注销一个平台设备&a…

专业和学校到底怎么选,兴趣和知名度到底哪个重要?

前言 2024高考已经落下帷幕&#xff0c;再过不久就到了激动人心的查分和填报志愿的时刻&#xff0c;在那天到来&#xff0c;小伙伴们就要根据自己的分数选取院校和专业&#xff0c;接下来我就以参加22年(破防年)河南高考的大二生来讲述一下我自己对于如何选取院校和专业的看法以…