当前位置: 首页 > 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​…...

高校AIGC检测越来越严格背后的原因:政策趋势和学生应对建议

高校AIGC检测越来越严格背后的原因&#xff1a;政策趋势和学生应对建议 超过六成高校已经把AIGC检测纳入论文审查流程。但真正了解检测原理的人不到一成。 我判断&#xff1a;高校AIGC检测趋严这件事&#xff0c;大多数人的恐慌来自不了解。搞清楚原理&#xff0c;应对起来没…...

终极指南:使用Docker快速部署WriteGPT AI创作平台

终极指南&#xff1a;使用Docker快速部署WriteGPT AI创作平台 【免费下载链接】WriteGPT 基于开源GPT2.0的初代创作型人工智能 | 可扩展、可进化 项目地址: https://gitcode.com/gh_mirrors/wri/WriteGPT WriteGPT是一款基于开源GPT-2.0的初代创作型人工智能框架&#x…...

cv_unet_image-colorization多分辨率适配实测:手机扫描件/胶片扫描图效果对比

cv_unet_image-colorization多分辨率适配实测&#xff1a;手机扫描件/胶片扫描图效果对比 1. 项目背景与技术原理 基于UNet架构深度学习模型开发的本地化图像上色工具&#xff0c;采用了阿里魔搭开源的图像上色算法。这个工具能够智能识别黑白图像中的物体特征、自然场景和人…...

AI技术原理--AI上下文窗口:为什么AI没有真正的记忆

99%的人都理解错了一个问题&#xff1a;AI真的会记得你吗&#xff1f; 很多人信誓旦旦跟我说&#xff1a;昨天我跟GPT聊了好久&#xff0c;今天一打开还能接着聊&#xff0c;这不是记忆是什么&#xff1f; 但如果我告诉你&#xff0c;它根本就不记得你——你是不是直接懵了&…...

颠覆式Alienware设备控制:500KB轻量工具实现10倍性能提升与个性化体验

颠覆式Alienware设备控制&#xff1a;500KB轻量工具实现10倍性能提升与个性化体验 【免费下载链接】alienfx-tools Alienware systems lights, fans, and power control tools and apps 项目地址: https://gitcode.com/gh_mirrors/al/alienfx-tools 当你启动Alienware电…...

后端消息投递可靠性:基于 RabbitMQ 的“双重防线-幂等闭环”模式

后端消息投递可靠性&#xff1a;基于 RabbitMQ 的“双重防线-幂等闭环”模式 一、 发送核心&#xff1a;rabbitTemplate.convertAndSend 重载全览 在 RabbitMQ 的“中控-工人”模式中&#xff0c;中控&#xff08;生产者&#xff09;发送指令的形式决定了任务的可靠性深度。 1.…...

BililiveRecorder:专业直播内容保存解决方案

BililiveRecorder&#xff1a;专业直播内容保存解决方案 【免费下载链接】BililiveRecorder 录播姬 | mikufans 生放送录制 项目地址: https://gitcode.com/gh_mirrors/bi/BililiveRecorder 在数字内容快速迭代的时代&#xff0c;如何永久保存有价值的直播内容成为许多创…...

基于TMS320F28033的20MHz手持式双踪袖珍示波器设计与实现

一、系统概述 设计实现了一款手持式、双通道、20MHz带宽的数字存储示波器&#xff0c;以TI TMS320F28033 DSP为核心控制器&#xff0c;结合FPGA与高速ADC&#xff0c;构建了集信号调理、高速采集、数据处理与显示于一体的便携式测量仪器。系统采用程控增益放大、DC/AC耦合电子切…...

证书创建方法说明

生成证书 方法一&#xff1a;合适&#xff08;临时测试&#xff0c;不需要管理&#xff09; 快速生成脚本&#xff08;一键完成&#xff09; 创建 create_lan_cert.sh&#xff1a; #!/bin/bash# 配置参数 IP_ADDR"192.168.1.100" # 修改为你的局域网IP DAYS365…...

Vue生命周期的灵魂拷问:created vs mounted,数据请求到底该在哪?

Vue生命周期的灵魂拷问&#xff1a;created vs mounted&#xff0c;数据请求到底该在哪&#xff1f; 在Vue.js的世界里&#xff0c;生命周期钩子是赋予开发者“上帝视角”的魔法&#xff0c;让我们能在组件从诞生到消亡的整个过程中&#xff0c;在精确的时机注入自定义逻辑。其…...