当前位置: 首页 > news >正文

LeetCode322. 零钱兑换

322. 零钱兑换

文章目录

    • [322. 零钱兑换](https://leetcode.cn/problems/coin-change/)
      • 一、题目
      • 二、题解
        • 方法一:完全背包二维数组
        • 方法二:一维数组
      • 三、注意


一、题目

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1

示例 2:

输入:coins = [2], amount = 3
输出:-1

示例 3:

输入:coins = [1], amount = 0
输出:0

提示:

  • 1 <= coins.length <= 12
  • 1 <= coins[i] <= 231 - 1
  • 0 <= amount <= 104

二、题解

方法一:完全背包二维数组

这个问题可以看作是一个完全背包问题的变形,即每种硬币的数量是无限的,而不是有限的。

  • 算法思路:

    • 首先,我们要定义一个二维数组 dp ,其中 dp[i][j] 表示用前 i+1 种硬币(即 coins[0]coins[i])凑成金额 j 所需的最少硬币个数。

    • 然后,我们要初始化 dp 数组,对于第一种硬币 coins[0] ,我们只需要看金额 j 是否能被它整除,如果能,那么 dp[0][j] = j / coins[0] ,否则 dp[0][j] = INT_MAX (表示无法凑成)。

    • 接下来,我们要逐行更新 dp 数组,对于第 i+1 种硬币 coins[i] ,我们有两种选择:使用它或者不使用它。如果不使用它,那么 dp[i][j] = dp[i-1][j] ,即和前 i 种硬币的结果一样;如果使用它,那么我们要保证金额 j 大于等于硬币面额 coins[i] ,并且减去这个面额后的金额能够被前 i+1 种硬币凑成,即 dp[i][j-coins[i]] != INT_MAX ,那么 dp[i][j] = dp[i][j-coins[i]] + 1 ,即在减去这个面额后的结果上加一。我们要在这两种选择中取最小值,即 dp[i][j] = min(dp[i-1][j], dp[i][j-coins[i]] + 1)

    • 最后,我们要返回 dp[coins.size() - 1][amount] ,即用所有种类的硬币凑成总金额所需的最少硬币个数。如果这个值等于 INT_MAX ,说明无法凑成,返回 -1 ;否则返回这个值。

  • 具体实现:

    • 可以用一个嵌套的循环来实现上述算法思路,外层循环遍历硬币种类,内层循环遍历金额。每次更新 dp[i][j] 时,先赋值为不使用当前硬币的结果,然后判断是否可以使用当前硬币,并更新为最小值。

    • 我们还需要注意一些边界情况,比如当金额为零时,返回零;当硬币数组为空时,返回 -1

    class Solution {
    public:int coinChange(vector<int>& coins, int amount) {if (amount == 0) return 0;vector<vector<int>> dp(coins.size(), vector<int>(amount + 1, INT_MAX));// 初始化for (int i = 0; i <= amount; i++) {if (i % coins[0] == 0) {dp[0][i] = i / coins[0];}}for (int i = 1; i < coins.size(); i++) {for (int j = 0; j <= amount; j++) {dp[i][j] = dp[i - 1][j];if (j >= coins[i] && dp[i][j - coins[i]]!=INT_MAX) {dp[i][j] = min(dp[i][j], dp[i][j - coins[i]] + 1);}}}return dp[coins.size() - 1][amount] == INT_MAX? -1 : dp[coins.size() - 1][amount];}
    };
    
  • 算法分析:

    • 时间复杂度:O(N*M),其中 N 是硬币种类数,M 是总金额。我们需要遍历所有的硬币和金额组合,每次更新一个状态值。

    • 空间复杂度:O(N*M),其中 N 是硬币种类数,M 是总金额。需要一个二维数组来存储所有的状态值。

方法二:一维数组

算法思路和具体实现和上面的二维数组差不多,不过我也copy了一下~

  • 算法思路:

    • 首先,我们定义一个一维数组 dp ,其中 dp[j] 表示凑成金额 j 所需的最少硬币个数。
    • 然后,我们初始化 dp 数组,对于金额为零的情况,我们不需要任何硬币,所以 dp[0] = 0 。对于其他金额,我们先设为一个很大的数,比如 INT_MAX ,表示无法凑成。
    • 接下来,我们遍历每种硬币 coins[i] ,对于每种硬币,我们从小到大遍历金额 j ,如果 j >= coins[i] ,说明我们可以用这种硬币来凑成金额 j ,那么我们就比较使用这种硬币和不使用这种硬币的结果,取最小值,即 dp[j] = min(dp[j], dp[j - coins[i]] + 1) 。注意这里和 01 背包问题的区别,01 背包问题中只能用一次每种物品,所以要从大到小遍历金额,避免重复使用;而完全背包问题中可以用无限次每种物品,所以要从小到大遍历金额,允许重复使用。
    • 最后,我们返回 dp[amount] ,即凑成总金额所需的最少硬币个数。如果这个值等于 INT_MAX ,说明无法凑成,返回 -1 ;否则返回这个值。
  • 具体实现:

    • 这个代码和上一个代码的区别在于,它只用了一个一维数组来存储状态值,而不是一个二维数组。这样做的原因是,对于每种硬币,我们只需要知道上一行的状态值就可以更新当前行的状态值,所以我们可以用一个一维数组来代替二维数组,节省空间。
    • 我们可以用一个嵌套的循环来实现上述算法思路,外层循环遍历硬币种类,内层循环遍历金额。每次更新 dp[j] 时,先判断是否可以使用当前硬币,并更新为最小值。
    • 我们还需要注意一些边界情况,比如当金额为零时,返回零;当硬币数组为空时,返回 -1
    class Solution {
    public:int coinChange(vector<int>& coins, int amount) {vector<int> dp(amount + 1, INT_MAX);dp[0] = 0;for (int i = 0; i < coins.size(); i++) {for (int j = 0; j <= amount; j++) {if (j >= coins[i] && dp[j - coins[i]]!=INT_MAX) {dp[j] = min(dp[j], dp[j - coins[i]] + 1);}}}return dp[amount] == INT_MAX? -1 : dp[amount];}
    };
    
  • 算法分析:

    • 时间复杂度:O(N*M),其中 N 是硬币种类数,M 是总金额。我们需要遍历所有的硬币和金额组合,每次更新一个状态值。
    • 空间复杂度:O(M),其中 M 是总金额。我们只需要一个一维数组来存储状态值。

三、注意

这道题不在乎硬币是排列还是组合,是因为我们只关心最少的硬币个数,而不关心硬币的顺序。换句话说,我们只要找到一种硬币组合,使得它的总金额等于目标金额,并且硬币个数最少,那么这种组合就是最优解,无论它的硬币顺序如何。例如,如果目标金额是 11 ,硬币面额是 [1, 2, 5] ,那么无论是 [5, 5, 1] 还是 [1, 5, 5] ,都是最优解,因为它们都只用了 3 个硬币。所以,不需要考虑排列和组合的区别,只需要考虑状态转移的逻辑。

相关文章:

LeetCode322. 零钱兑换

322. 零钱兑换 文章目录 [322. 零钱兑换](https://leetcode.cn/problems/coin-change/)一、题目二、题解方法一&#xff1a;完全背包二维数组方法二&#xff1a;一维数组 三、注意 一、题目 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 a…...

AUTOSAR扫盲贴--不是黑神话【基本概念和方法论】

猴子纵有72搬变化,也跳不出如来的手掌 目录 1. 引言 2. AUTOSAR的基本概念 2.1. AUTOSAR的架构和组成部分 2.2. AUTOSAR的规范和...

python抠图(去水印)开源库lama-cleaner入门应用实践

1. 关于 Lama Cleaner Lama Cleaner 是由 SOTA AI 模型提供支持的免费开源图像修复工具。可以从图片中移除任何不需要的物体、缺陷和人&#xff0c;或者擦除并替换&#xff08;powered by stable diffusion&#xff09;图片上的任何东西。 特征&#xff1a; 完全免费开源&am…...

Nginx可视化管理工具结合cpolar实现远程访问内网服务

前言 Nginx Proxy Manager 是一个开源的反向代理工具&#xff0c;不需要了解太多 Nginx 或 Letsencrypt 的相关知识&#xff0c;即可快速将你的服务暴露到外部环境&#xff0c;并且支持 SSL 配置。基于 Tabler 的美观且安全的管理界面,无需了解 Nginx 即可轻松创建转发域、重定…...

CCC数字钥匙设计【BLE】 --建立安全测距

1、建立安全测距Establish Secure Ranging 车端总共有三种建立安全测距的方式&#xff0c;具体如下&#xff1a; 1) Optimal Flow 2) Sub-Optimal Flow 3) Ranging Recovery Flow 为了确定建立安全测距需要执行哪条流程&#xff0c;车辆需要进行以下流程选择。当车辆和设备…...

Ubuntu22.04 Opencv4.5.1 CPU和GPU编译攻略,Opencv CPU和GPU编译保姆教程 亲自测试。

1、安装opencv依赖 安装时最好更换一下源。 sudo apt-get -y update sudo apt-get -y install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev sudo apt-get -y install libgtk-3-dev gfortran openexr libatlas-base-dev python3-dev pyt…...

常识判断 --- 党史

目录 中共1~3大 例题 国民党 例题 中共4~5大 例题 中共起义~会议 例题 中共六届六中全会&#xff08;1938年9月&#xff09; 中共七大&#xff08;1945年4月&#xff09; 例题 中共七届二中全会 例题 中共8~10大 中共11~12届全会 例题 中共13~14大 …...

Rust 基础再理解

Rust堆栈 Rust中各种类型的值默认都存储在栈中&#xff0c;除非显式地使用Box::new()将它们存放在堆上&#xff0c;但数据要存放在栈中&#xff0c;要求其数据类型的大小已知。对于静态大小的类型&#xff0c;可直接存储在栈上&#xff0c;如裸指针、布尔、字符、整数浮点数&a…...

Opencv cuda版本在ubuntu22.04中安装办法,解决Could NOT find CUDNN的办法

文章目录 概要下载cuda的runfile版本配置环境变量官网下载cudann安装Opencv依赖包下载opencv和opencv_contrib并解压准备编译安装anaconda环境执行编译命令安装OpenCV并检查是否安装成功 概要 解决以下安装问题&#xff1a; -- Could NOT find CUDNN: Found unsuitable versi…...

全网首发YOLOv8暴力涨点:Gold-YOLO,遥遥领先,超越所有YOLO | 华为诺亚NeurIPS23

💡💡💡本文独家改进:提出了全新的信息聚集-分发(Gather-and-Distribute Mechanism)GD机制,Gold-YOLO,替换yolov8 head部分 实现暴力涨点 Gold-YOLO | 亲测在多个数据集能够实现大幅涨点 💡💡💡Yolov8魔术师,独家首发创新(原创),适用于Yolov5、Yolov7、…...

BD就业复习第四天

1. 布隆过滤器怎么实现去重 布隆过滤器是一种用于快速检查一个元素是否可能存在于一个大集合中的数据结构&#xff0c;但它并不适用于精确去重。因为布隆过滤器具有一定的误判率&#xff08;可能会将不存在的元素误判为存在&#xff09;&#xff0c;所以不能确保完全的去重。但…...

数据结构 | 树

树 树是n&#xff08;n>0&#xff09;个结点的有限集。当n 0时&#xff0c;称为空树。在任意一棵非空树中应满足&#xff1a; 有且仅有一个特定的称为根的结点。当n>1时&#xff0c;其余节点可分为m&#xff08;m>0&#xff09;个互不相交的有限集T1,T2,…,Tm&#…...

Android11 适配

一、修改targetSdkVersion为30 将build.gradle的目标版本targetSdkVersion修改为30&#xff08;Android 11&#xff09; targetSdkVersion 30Android11的改变改变主要影响以Adnroid11 为目标版本的应用&#xff08;targetSdkVersion>30才有影响&#xff09;&#xff0c;和所…...

UML基础与应用之对象图

什么是对象图&#xff1f; 对象图表示一组对象及它们之间的关系&#xff0c;是某一时刻系统详细信息的快照&#xff0c;描述系统交互的静态图形&#xff0c;它由协作的对象组成&#xff0c;但不包含在对象之间传递的任何消息。因为对象是类的实例化&#xff0c;所以说某一时刻…...

英码科技精彩亮相火爆的IOTE 2023,多面赋能AIoT产业发展!

9月20日至22日&#xff0c;在这金秋飒爽的季节&#xff0c;为期三天的IOTE 2023第二十届国际物联网展深圳站在深圳国际会展中心盛大举行。英码科技精彩亮相本届展会&#xff0c;并在同期举办的AIoT视觉物联产业生态大会发表了主题演讲&#xff0c;与生态伙伴们共同探讨AIoT产业…...

400G QSFP-DD FR4 与 400G QSFP-DD FR8光模块:哪个更适合您的网络需求?

QSFP-DD 光模块随着光通信市场规模的不断增长已成为400G市场中客户需求量最高的产品。其中400G QSFP-DD FR4和400G QSFP-DD FR8光模块都是针对波分中距离传输&#xff08;2km&#xff09;的解决方案&#xff0c;它们之间有什么不同&#xff1f;应该如何选择应用&#xff1f;飞速…...

【Android】Kotlin 中的 apply、let、with、also、run 到底有啥区别?

一、图示 二、apply apply 函数接收一个对象并返回该对象本身。它允许您在对象上执行一些操作&#xff0c;同时仍然返回原始对象。 这个函数的语法为&#xff1a; fun <T> T.apply(block: T.() -> Unit): T 其中&#xff0c;T 是对象的类型&#xff0c;block 是一…...

设计模式——职责链模式

职责链模式 职责链模式职责链模式解决什么问题&#xff1f;职责链模式实现 职责链模式 使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。将这个对象练成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;知道有一个对象处理它为止 …...

小程序自定义tabbar,中间凸起

微信小程序自带tabbar&#xff0c;但无法实现中间按钮凸起样式和功能&#xff0c;因此按照设计重新自定义一个tabbar 1、创建tabbar文件&#xff0c;与pages同级创建一个文件夹&#xff0c;custom-tab-bar,里面按照设计图将底部tabbar样式编写 <view class"tab-bar&q…...

数据结构-顺序栈C++示例

栈(stack)是限定仅在表尾进行插入或删除操作的线性表。 对栈来说&#xff0c;表尾端称为栈顶(top)&#xff0c; 表头端称为栈底(bottom)&#xff0c;不含元素的空表称为空栈。 假设栈 S ( a 1 , a 2 , a 3 , ⋯ , a n ) S(a_1,a_2,a_3,\cdots,a_n) S(a1​,a2​,a3​,⋯,an​…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...