牛客热题:兑换零钱(一)

2024-06-15 18:52
文章标签 牛客 热题 兑换 零钱

本文主要是介绍牛客热题:兑换零钱(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

📟作者主页:慢热的陕西人

🌴专栏链接:力扣刷题日记

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

在这里插入图片描述

文章目录

  • 牛客热题:兑换零钱(一)
    • 题目链接
    • 方法一:动态规划
      • 思路
      • 代码
      • 复杂度
    • 方法二:递归
      • 思路
      • 总结思路:
      • 代码
      • 复杂度

牛客热题:兑换零钱(一)

题目链接

兑换零钱(一)_牛客题霸_牛客网 (nowcoder.com)

方法一:动态规划

思路

首先我们思考当arr中最小的零钱是1时,那么这时候是凑成aim的最大钱数,aim个1块钱。

①状态表示:

d p [ i ] dp[i] dp[i]表示的是i块钱用数组中的零钱表示的最少钱数。

②状态转化:

​ 显然 d p [ i ] dp[i] dp[i]的值可以从 d p [ i − a r r [ j ] ] dp[i - arr[j]] dp[iarr[j]]的状态获取,但是题目要求最小值,所以取一个min

d p [ i ] = m i n ( d p [ i ] , d p [ i − a r r [ j ] ] + 1 ) dp[i] = min(dp[i], dp[i - arr[j]] + 1) dp[i]=min(dp[i],dp[iarr[j]]+1)

③填表顺序:

​ 对于dp数组的话,因为dp的当前状态需要用到之前状态,所以按照从左的到右的顺序

​ 对于原数组arr,这个数组的话不牵扯到状态转移,只需要遍历就好了,习惯上也从左到右来遍历

④初始化:

对于dp数组,开始时除了 d p [ 0 ] = 0 dp[0] = 0 dp[0]=0,其余的dp状态都应该设定为对应的最大值+1,也就是aim + 1;

⑤返回值:

代码

    int minMoney(vector<int>& arr, int aim) {//创建dp数组vector<int> dp(aim + 1, aim + 1);dp[0] = 0;for(int i = 0; i <= aim; ++i){for(int j = 0; j < arr.size(); ++j){if(i >= arr[j])dp[i] = min(dp[i], dp[i - arr[j]] + 1);}}return dp[aim] > aim ? -1 : dp[aim];}

复杂度

时间复杂度: O ( a i m ∗ a r r . s i z e ( ) ) O(aim * arr.size()) O(aimarr.size()), 遍历dp数组的同时去遍历原数组。

空间复杂度: O ( a i m + 1 ) O(aim + 1) O(aim+1),额外使用了一个dp数组,长度是aim+1。

方法二:递归

思路

  1. recursion 函数

    • 这是一个递归函数,用于计算组合达到目标金额 aim 所需的最小硬币数量。
    • 参数包括 arr(硬币面值数组)、aim(目标金额)、dp(用于记录中间结果的数组)。
  2. 基础情况

    • 如果 aim < 0,表示当前的组合方式超过了目标金额,返回 -1
    • 如果 aim == 0,表示当前的组合方式正好等于目标金额,返回 0(硬币数量为0)。
    • 如果 dp[aim - 1] != 0,说明 aim 这个金额已经计算过了,直接返回 dp[aim - 1]
  3. 递归求解

    • 初始化 MinINT_MAX,用于记录当前情况下的最小硬币数量。
    • 遍历所有硬币面值 arr[i],对于每个面值,计算使用该面值时剩余金额 aim - arr[i] 的最小硬币数量 res
    • 如果 res >= 0(说明可以组合成功)且 res + 1 比当前 Min 小,则更新 Min
  4. 更新结果

    • dp[aim - 1] 设置为 Min,如果 Min 仍然是 INT_MAX,表示无法组合成 aim,返回 -1,否则返回 Min
  5. minMoney 函数

    • 这是主函数,初始化了 dp 数组并调用了 recursion 函数来求解最小硬币数量。
    • 如果 aim < 1,直接返回 0,因为小于等于 0 的金额不需要硬币。

总结思路:

  • 使用递归方法和动态规划思想,通过 dp 数组记录中间结果,避免重复计算,提高效率。
  • 递归函数中每次选择一个硬币面值,尝试组合达到目标金额,找出最少的硬币数量。
  • 如果某个金额已经计算过,直接返回已存储的结果,避免重复计算,提高效率。

代码

    int recurison(vector<int>& arr, int aim, vector<int>& dp){if(aim < 0) return -1;if(aim == 0) return 0;if(dp[aim - 1] != 0)return dp[aim - 1];int Min = INT_MAX;//遍历所有的值for(int i = 0; i < arr.size(); ++i){//递归运算选择当前的面值int res = recurison(arr, aim - arr[i], dp);//获取最小值if(res >= 0 && res < Min)Min = res + 1;}//更新最小值dp[aim - 1] = Min == INT_MAX ? -1 : Min;return dp[aim - 1]; }int minMoney(vector<int>& arr, int aim) {if(aim < 0) return -1;vector<int> dp(aim, 0);return recurison(arr, aim, dp);}

复杂度

  • 时间复杂度: O ( n ∗ a i m ) O(n * aim) O(naim),一共需要计算aim个状态的答案,每个状态需要枚举n个面值
  • 空间复杂度: O ( a i m ) O(aim) O(aim),递归栈深度及辅助数组的空间

这篇关于牛客热题:兑换零钱(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1064290

相关文章

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

【LeetCode热题100】前缀和

这篇博客共记录了8道前缀和算法相关的题目,分别是:【模版】前缀和、【模版】二维前缀和、寻找数组的中心下标、除自身以外数组的乘积、和为K的子数组、和可被K整除的子数组、连续数组、矩阵区域和。 #include <iostream>#include <vector>using namespace std;int main() {//1. 读取数据int n = 0, q = 0;ci

代码随想录训练营day37|52. 携带研究材料,518.零钱兑换II,377. 组合总和 Ⅳ,70. 爬楼梯

52. 携带研究材料 这是一个完全背包问题,就是每个物品可以无限放。 在一维滚动数组的时候规定了遍历顺序是要从后往前的,就是因为不能多次放物体。 所以这里能多次放物体只需要把遍历顺序改改就好了 # include<iostream># include<vector>using namespace std;int main(){int n,m;cin>>n>>m;std::vector<i

牛客小白月赛100部分题解

比赛地址:牛客小白月赛100_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ A.ACM中的A题 #include<bits/stdc++.h>using namespace std;#define ll long long#define ull = unsigned long longvoid solve() {ll a,b,c;cin>>a>>b>

牛客小白月赛100(A,B,C,D,E,F三元环计数)

比赛链接 官方讲解 这场比较简单,ABC都很签到,D是个不太裸需要预处理的 B F S BFS BFS 搜索,E是调和级数暴力枚举,F是三元环计数。三元环考的比较少,没见过可能会偏难。 A ACM中的A题 思路: 就是枚举每个边变成原来的两倍,然后看看两短边之和是否大于第三边即可。 不能只给最短边乘 2 2 2,比如 1 4 8 这组数据,也不能只给第二短边乘 2 2 2,比

代码随想录算法训练营Day37|完全背包问题、518.零钱兑换II、377. 组合总和 Ⅳ、70. 爬楼梯(进阶版)

完全背包问题                  和01背包最大区别就是一个物品可以重复放多次,因此遍历空间时可以从前往后。 import java.util.*;public class Main{public static void main (String[] args) {Scanner sc = new Scanner(System.in);int m = sc.nextInt

笔试强训,[NOIP2002普及组]过河卒牛客.游游的水果大礼包牛客.买卖股票的最好时机(二)二叉树非递归前序遍历

目录 [NOIP2002普及组]过河卒 牛客.游游的水果大礼包 牛客.买卖股票的最好时机(二) 二叉树非递归前序遍历 [NOIP2002普及组]过河卒 题里面给的提示很有用,那个马的关系,后面就注意,dp需要作为long的类型。 import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息publ

每日OJ_牛客_求和(递归深搜)

目录 牛客_求和(递归深搜) 解析代码 牛客_求和(递归深搜) 求和_好未来笔试题_牛客网 解析代码         递归中每次累加一个新的数,如果累加和大于等于目标,结束递归。此时如果累加和正好等于目标,则打印组合。向上回退搜索其它组合。此题本身就是一个搜索的过程,找到所有的组合。 #include <iostream>#include <cmath>#in

代码随想录:322. 零钱兑换

322. 零钱兑换 class Solution {public:int coinChange(vector<int>& coins, int amount) {vector<int> dp(10005,INT_MAX);//由于后面要取最小值,所以初始大一些dp[0]=0;//总金额为0个数一定为0for(int i=0;i<coins.size();i++){for(int j=coins

牛客《剑指Offer》 -- 数值的整数次方

题目描述 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 思路 特别注意负数的情况,出现负数,将其转化为正数然后求倒数。 class Solution {public:double Power(double base, int exponent) {double total = 1;bool flag = false