每日OJ题_完全背包②_力扣322. 零钱兑换

目录

力扣322. 零钱兑换

问题解析

解析代码

优化代码(滚动数组)


力扣322. 零钱兑换

322. 零钱兑换

难度 中等

给你一个整数数组 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] <= 2^31 - 1
  • 0 <= amount <= 10^4
class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {

    }
};

问题解析

先看能不能将问题转化成我们熟悉的题型。

  • 在一些物品中挑选一些出来,然后在满足某个限定条件下,解决一些问题,大概率是背包模型;
  • 由于每一个物品都是无限多个的,因此是一个完全背包问题。接下来的分析就是基于完全背包的方式来

状态表示: dp[i][j] 表示:从前 i 个硬币中挑选,总和正好等于 j ,所有的选法中,最少的硬币个 数。

状态转移方程:

        线性 dp 状态转移方程分析方式,一般都是根据最后一步的状况,来分情况讨论。但是最后一个物品能选很多个,因此需要分很多情况:

  • 选 0 个第 i 个硬币:此时相当于就是去前 i - 1 个硬币中挑选,总和正好等于 j 。 此时最少的硬币个数为 dp[i - 1][j] 
  • 选 1 个第 i 个硬币:此时相当于就是去前 i - 1 个硬币中挑选,总和正好等于 j - v[i] 。因为挑选了一个 i 硬币,此时最少的硬币个数为 dp[i - 1][j - coins[i]] + 1 ;
  • 选 2 个第 i 个硬币:此时相当于就是去前 i - 1 个硬币中挑选,总和正好等于 j - 2 * coins 。因为挑选了两个 i 硬币,此时最少的硬币个数为 dp[i - 1][j - 2 * coins[i]] + 2 ;
  • ......

综上,状态转移方程为:

dp[i][j]=min(dp[i - 1][j], dp[i - 1][j - coins[i]] + 1, dp[i - 1][j - 2*coins[i]] + 2 ......)

        这时发现,计算一个状态的时候,需要一个循环才能搞定的时候,我们要想到去优化。优化的方向就是用一个或者两个状态来表示这一堆的状态,通常就是用数学的方式做一下等价替换。

        发现第二维是有规律的变化的,因此去看看 dp[i][j - v[i]] 这个状态: dp[i][j - v[i]]=min(dp[i - 1][j - coins[i]] + 1,dp[i - 1][j - 2*coins[i]]] + 2,dp[i - 1] [j - 3*coins[i]] + 3......)

        因此可以修改我们的状态转移方程为: dp[i][j] = min(dp[i - 1][j], dp[i][j - coins[i]] + 1) 。(j >= coins[i] , dp[i][j - coins[i]] 存在 。)(如果初始化多开一行一列,找coins数组要减一)

有个技巧,就是相当于把第二种情况 dp[i - 1][j - coins[i]] + 1 ⾥ ⾯的 i - 1 变成 i 即可。

初始化: dp[0[0]为0,初始化第一行即可。 这里因为取 min ,所以可以把无效的地方设置成无穷大 (0x3f3f3f3f) 因为这里要求正好凑成总和为 j ,因此,需要把第一行除了第一个位置的元素,都设置成无穷大。

填表顺序: 根据状态转移方程,仅需从上往下填表。

返回值: 根据状态表示,返回 dp[n][amount] 。由于最后可能凑不成总数为 amount 的情况,因此返回之前需要特判一下。


解析代码

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        const int INF = 0x3f3f3f3f; // 无穷大的一半
        int n = coins.size();
        vector<vector<int>> dp(n + 1, vector<int>(amount + 1, INF));
        // dp[i][j]表示:从前i个硬币中挑选,总和正好等于j,所有的选法中,最少的硬币个数
        dp[0][0] = 0;
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 0; j <= amount; ++j)
            {
                if(j >= coins[i - 1])
                    dp[i][j] = min(dp[i - 1][j], dp[i][j - coins[i - 1]] + 1);
                else
                    dp[i][j] = dp[i - 1][j];
            }
        }
        return dp[n][amount] >= INF ? -1 : dp[n][amount];
    }
};

优化代码(滚动数组)

背包问题基本上都是利用滚动数组来做空间上的优化:

  1. 利用滚动数组优化。
  2. 直接在原始代码上修改。

在完全背包问题中,优化的结果为:

  1. 仅需删掉所有的横坐标。

(填一行数组的值的时候要用到前面新填的值,所以依旧是从左往右遍历,01背包是从右往左)

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        const int INF = 0x3f3f3f3f; // 无穷大的一半
        int n = coins.size();
        vector<int> dp(amount + 1, INF);
        dp[0] = 0;
        for(int i = 1; i <= n; ++i)
        {
            for(int j = coins[i - 1]; j <= amount; ++j)
            {
                dp[j] = min(dp[j], dp[j - coins[i - 1]] + 1);
            }
        }
        return dp[amount] >= INF ? -1 : dp[amount];
    }
};

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

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

相关文章

外观模式:简化复杂系统的统一接口

在面向对象的软件开发中&#xff0c;外观模式是一种常用的结构型设计模式&#xff0c;旨在为复杂的系统提供一个简化的接口。通过创建一个统一的高级接口&#xff0c;这个模式帮助客户端通过一个简单的方式与复杂的子系统交互。本文将详细介绍外观模式的定义、实现、应用场景以…

链表拓展之双向链表

前言 在前面已经总结了单链表&#xff0c;有了单链表的基础会很好理解双链表的实现&#xff0c;忘记了可以跳转——>http://t.csdnimg.cn/GFPk9 接下来就由我带着各位看官来认识今天的主角吧~ 什么是双向链表 在单链表的基础上&#xff0c;它有两个方向的链接&#xff0c;一…

加强fou循环的坑

今天遇到了一个有趣的事情&#xff0c;使用加强fou循环操作list时&#xff0c;会报错并发操作异常。 直到看了编译类&#xff0c;才发现&#xff0c;加强fou循环其实就是通过迭代器操作&#xff1a; 这里就会出现一个问题&#xff0c;迭代器在取出值时&#xff0c;就回去检测这…

分析ARP解析过程

一、实验环境 主机A和主机B连接到交换机&#xff0c;并与一台路由器互连&#xff0c;如图7.17所示&#xff0c;路由器充当网关。 图7.17 二、需求描述 查看 ARP 相关信息,熟悉在PC 和 Cisco 设备上的常用命令,设置主机A和主机B为同一个网段网关设置为路由接口地址。 三、推…

基于Python的景区票务人脸识别系统(V2.0)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

排列特征重要性(Permutation Feature Importance)

5个条件判断一件事情是否发生&#xff0c;每个条件可能性只有2种&#xff08;发生或者不发生&#xff09;&#xff0c;计算每个条件对这件事情发生的影响力。排列特征重要性模型的程序。 例一 在机器学习领域&#xff0c;排列特征重要性&#xff08;Permutation Feature Impor…

QT 串口助手 学习制作记录

QT 串口助手qt 学习制作记录 参考教程&#xff1a;​​​​​​QT初体验&#xff1a;手把手带你写一个自己的串口助手_qt设计串口助手的流程图-CSDN博客 Qt之串口编程&#xff08;添加QSerialPort模块&#xff09;_如何安装 qt串口模块教程-CSDN博客 串口调试助手&#xff1…

2.2 @SpringBootApplication

2.2 SpringBootApplication 在前文的介绍中&#xff0c;读者已经了解到SpringBootApplication注解是加在项目的启动类上的。 SpringBootApplication实际上是一个组合注解&#xff0c;定义如下&#xff1a; SpringBootConfiguration EnableAutoConfiguration ComponentScan(exc…

python-常用数据结构(2)

6、某企业为职工发放奖金:如果入职超过5年,且销售业绩超过15000元的员工,奖金比例为0.2;销售业绩超过10000元的员工,奖金比例为0.15:销售业绩超过5000元的员工,奖金比例为0.1;其他奖金比例为0.05。如果是人职不超过5年,且销售业绩超过4000的员工,奖金比例为0.045;否则为0.01。输…

使用Python模仿文件行为

在Python中&#xff0c;你可以通过文件操作函数&#xff08;如open()函数&#xff09;以及模拟输入输出流的库&#xff08;如io模块&#xff09;来模拟文件行为。下面是一些示例&#xff0c;展示了如何使用这些工具在Python中模拟文件行为。 1、问题背景 在编写一个脚本时&…

深度挖掘响应式模式的潜力,从而精准优化AI与机器学习项目的运行效能,引领技术革新潮流

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f525; 转载自热榜文章&#xff1a;探索设计模式的魅力&#xff1a;深度挖掘响应式模式的…

基于Docker构建CI/CD工具链(六)使用Apifox进行自动化测试

添加测试接口 在Spring Boot Demo项目里实现一个简单的用户管理系统的后端功能。具体需求如下&#xff1a; 实现了一个RESTful API&#xff0c;提供了以下两个接口 &#xff1a; POST请求 /users&#xff1a;用于创建新的用户。GET请求 /users&#xff1a;用于获取所有用户的列…

爬取东方财富股票代码

我们打开东方财富网站&#xff1a;http://quote.eastmoney.com/stocklist.html 假如懒得爬&#xff0c;也可以用现成的股票数据源&#xff1a;https://stockapi.com.cn 这展示了所有股票信息&#xff0c;不过需要我们分页去爬取 我们可以查询具体的html代码&#xff1a; <…

微信小程序-绘制图片并分享下载(painter)

1、引入painter插件 painter官网地址 1.1 可通过官网的方法引入painter插件&#xff0c; 官方插件下载地址 1.2 可下载本文附带的插件包直接引入 1.2.1 复制下载下来的文件中的painter文件夹&#xff0c;将其放在components目录下 1.2.2 页面中引入并使用 .json {"…

边缘计算网关主要有哪些功能?-天拓四方

随着物联网&#xff08;IoT&#xff09;的快速发展和普及&#xff0c;边缘计算网关已经成为了数据处理和传输的重要枢纽。作为一种集成数据采集、协议转换、数据处理、数据聚合和远程控制等多种功能的设备&#xff0c;边缘计算网关在降低网络延迟、提高数据处理效率以及减轻云数…

hot100 -- 链表(中)

不要觉得力扣核心代码模式麻烦&#xff0c;它确实比不上ACM模式舒服&#xff0c;可以自己处理输入输出 只是你对 链表 和 return 的理解不到位 &#x1f442; ▶ 屿前世 (163.com) &#x1f442; ▶ see you tomorrow (163.com) 目录 &#x1f382;两数相加 &#x1f6a9;删…

Python 全栈体系【四阶】(二十八)

第五章 深度学习 四、TensorFlow 1. Tensorflow 简介 1.1 什么是 Tensorflow TensorFlow 由谷歌人工智能团队谷歌大脑&#xff08;Google Brain&#xff09;开发和维护的开源深度学习平台&#xff0c;是目前人工智能领域主流的开发平台&#xff0c;在全世界有着广泛的用户群…

项目升级到jdk21后 SpringBoot相关组件的适配

了解到jdk21是一个LTS版本&#xff0c;可以稳定支持协程的功能。经过调研&#xff0c;将目前线上的jdk8升级到21&#xff0c;使用协程提升并发性能。 目前系统使用springBoot 2.0.3.RELEASE&#xff0c;并且引入了mybatis-spring-boot-starter、spring-boot-starter-data-redi…

电商技术揭秘22:智能仓储与物流优化(上)

相关系列文章 电商技术揭秘一&#xff1a;电商架构设计与核心技术 电商技术揭秘二&#xff1a;电商平台推荐系统的实现与优化 电商技术揭秘三&#xff1a;电商平台的支付与结算系统 电商技术揭秘四&#xff1a;电商平台的物流管理系统 电商技术揭秘五&#xff1a;电商平台…

Hot100【十一】: 347. 前 K 个高频元素

class Solution {public int[] topKFrequent(int[] nums, int k) {// 1.建立hash表来存储每个元素以及它的频率HashMap<Integer, Integer> num2Fre new HashMap<Integer, Integer>();for (int num : nums) {num2Fre.put(num, num2Fre.getOrDefault(num, 0) 1);}/…
最新文章