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

前言

思路及算法思维,指路 代码随想录。
题目来自 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]] 明显更难以理解一些。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大模型技术如何构建金融领域的创新生态?

前言 近年来&#xff0c;人工智能技术不断迭代与突破&#xff0c;助力各行各业加速迈向智能化&#xff0c;其中在金融领域的运用逐渐加深&#xff0c;为银行、保险、基金、券商等金融机构实现数智化转型提供引擎动能。而大模型时代的到来&#xff0c;则为金融智能的发展引入了…

vue3-openlayers 点击多边形弹框,高亮多边形,自定义属性传递,鼠标悬浮多边形上动态修改鼠标样式

本篇介绍一下使用vue3-openlayers点击多边形弹框&#xff0c;高亮多边形&#xff0c;自定义属性传递&#xff0c;鼠标悬浮多边形上动态修改鼠标样式 1 需求 加载天地图&#xff0c;polygon传递自定义属性标悬浮在polygon上&#xff0c;根据自定义属性&#xff0c;动态修改鼠标…

【深度学习】sdwebui A1111 加速方案对比,xformers vs Flash Attention 2

文章目录 资料支撑资料结论sdwebui A1111 速度对比测试sdxlxformers 用contorlnet sdxlsdpa&#xff08;--opt-sdp-no-mem-attention&#xff09; 用contorlnet sdxlsdpa(--opt-sdp-attention) 用contorlnet sdxl不用xformers或者sdpa ,用contorlnet sdxl不用xformers或者sdpa …

35 Debian如何配置Postfix+Dovecot实现邮件加密

作者:网络傅老师 特别提示:未经作者允许,不得转载任何内容。违者必究! Debian如何配置Postfix+Dovecot实现邮件加密 《傅老师Debian知识库系列之35》——原创 ==前言== 傅老师Debian知识库特点: 1、拆解Debian实用技能; 2、所有操作在VMware虚拟机实测完成; 3、致力于…

Neo4j 创建关系

Neo4j 创建关系 在 Noe4j 中&#xff0c;关系是我们用来连接图的两个节点的元素。 这些关系具有数据的方向、类型和形式模式。 本章教你如何 建立关系在现有节点之间创建关系使用标签和属性创建关系 建立关系 我们可以使用 CREATE 子句创建关系。 我们将在方括号[]中指定关系…

工业自动化中OBC充电机测试负载箱的应用

在工业自动化中&#xff0c;OBC充电机是电动汽车和混合动力汽车的重要组成部分。它的主要功能是为电动汽车的电池组提供电能&#xff0c;保证车辆的正常运行。为了保证OBC充电机的性能和安全性&#xff0c;通常需要对其进行严格的测试。在这个过程中&#xff0c;负载箱是一种非…

PySide(PyQt)的特殊按钮(互锁、自锁、独占模式)

界面图: Qt Designer中创建窗口,放置一个QGroupBox,命名为btnStation,这就是自定义的按钮站,按钮站里放置6个按钮。自锁按钮相当于电器中的自锁功能的按钮,每按一次状态反转并保持不变。独占按钮也是自锁功能的按钮,不同的是当独占按钮为ON时,其余所有按钮均被置为OFF…

点亮LED灯(TMS570LS31HDK)

一、安装Code Composer studio&#xff08;CCS&#xff09; 1.ccs下载地址 2.ccs安装 学习文档 二、安装Hal Code Generator 下载地址 三、创建新的CCS项目&#xff08;TMDS570LS31HDK&#xff09; 详细步骤学习博客&#xff08;推荐这里学习&#xff09; 以下是大致步骤…

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

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

Fastjson 结合 jdk 原生反序列化的利用手法 ( Aliyun CTF )

2023 Aliyun CTF ezbean是一道CTF java反序列化题目。 题目的目的是让选手通过一个java原生反序列化入口&#xff0c;最终达成RCE。本文对题目的几种解法做了具体的分析&#xff0c;主要分为预期解法和非预期解法两种思路。通过对Fastjson在反序列化的行为分析&#xff0c;从两…

GIT----使用技巧之保存现场回退新建分支继续开发

GIT----使用技巧之保存现场回退新建分支继续开发 前言&#xff1a; 故事是这样的&#xff0c;有一个比较复杂的项目使用的是STM32F103VCT6&#xff08;资源flash-256k,RAM-48k&#xff09;,开发到一半发现RAM不够用了&#xff0c;换容量更大的芯片STM32F103VGT6&#xff08;资源…

0.4 隔行扫描(Interlaced Scan)简介

0.4 隔行扫描简介 隔行扫描&#xff08;Interlaced Scan&#xff09;是一种将图像显示在扫描式的显示设备上的方法&#xff0c;例如阴极射线管&#xff08;CRT&#xff09;。 隔行扫描设备交替扫描图像的奇场&#xff08;图像的所有奇数行&#xff0c;1、3、5&#xff09;和偶…

Excel 找出最大值及其相邻的 N 个成员

某列都是数值&#xff1a; A1132213464215496973482396101113712491342144015151631171718114719182030212222423252419251326272738283029163012312332333233419351436463723383739384028 请找出最大值及其相邻的 10 个成员&#xff0c;注意越界检查&#xff0c;实际符合条件…

银行数仓项目实战(四)--了解银行业务(存款)

文章目录 项目准备存款活期定期整存整取零存整取存本取息教育储蓄定活两便通知存款 对公存款对公账户协议存款 利率 项目准备 &#xff08;贴源层不必写到项目文档&#xff0c;因为没啥操作没啥技术&#xff0c;只是数据。&#xff09; 可以看到&#xff0c;银行的贴源层并不紧…

Fisnar Liquid Control 操作维修手LC Pump Manual Twinmixer Maintenance 中文

Fisnar Liquid Control 操作维修手LC Pump Manual Twinmixer Maintenance 中文

基于springboot实现交通管理在线服务系统项目【项目源码+论文说明】

基于springboot实现交通管理在线服务系统演示 摘要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装交通管理在线服…

【计算机网络仿真实验-实验2.7】单臂路由

实验2.7 单臂路由 1. 实验拓扑图 2. 测试连通性 测试PC1 PC2 PC3 之间的连通性 无法ping通&#xff0c;因为它们处在不同的网段&#xff0c;而二层交换机不具备路由功能&#xff0c;因此没办法接通 3. 在交换机上创建vlan10&#xff0c;并将端口0/2划分到vlan10中 Switch>…

CUDA系列-Mem-9

这里写目录标题 Static Architecture.Abstractions provided by CUSW_UNIT_MEM_MANAGERMemory Object (CUmemobj) Memory Descriptor(CUmemdesc)Memory Block(CUmemblock)Memory BinsSuballocations in Memory BlockFunctional description Memory Manager 你可能觉得奇怪&…

分班查询,一键发布,老师们都在用的分班查询系统

老师们开学季马上又要到了&#xff0c;回想起了每年埋头苦干&#xff0c;对着一堆堆的学生名单&#xff0c;一个个手动分配班级&#xff0c;再一个个通知家长和学生的日子&#xff0c;那种手忙脚乱&#xff0c;生怕出错的紧张感&#xff0c;是不是还历历在目&#xff1f;每次分…

工作人员能从轧钢测径仪上获取哪些有效信息?

轧钢测径仪安装在轧钢生产线中&#xff0c;无论是热轧还是冷轧&#xff0c;都不能阻挡测径仪的高速无损高精检测。它采用八轴测量系统&#xff0c;能全方位检测外径尺寸&#xff0c;并且配备了测控软件系统&#xff0c;为工作人员提供更加丰富的产线信息。 普通轧钢测径仪能获…