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

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

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

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

文章目录

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

题目链接

兑换零钱(一)_牛客题霸_牛客网 (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[i−arr[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[i−arr[j]]+1)

③填表顺序:

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

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

④初始化:

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

⑤返回值:

代码

cpp 复制代码
    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(aim∗arr.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 数组记录中间结果,避免重复计算,提高效率。
  • 递归函数中每次选择一个硬币面值,尝试组合达到目标金额,找出最少的硬币数量。
  • 如果某个金额已经计算过,直接返回已存储的结果,避免重复计算,提高效率。

代码

cpp 复制代码
    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(n∗aim),一共需要计算aim个状态的答案,每个状态需要枚举n个面值
  • 空间复杂度: O ( a i m ) O(aim) O(aim),递归栈深度及辅助数组的空间
相关推荐
minji...2 分钟前
数据结构 算法复杂度(1)
c语言·开发语言·数据结构·算法
black_blank39 分钟前
st表 && csp37 第四题 集体锻炼
java·数据结构·算法
我爱Jack42 分钟前
Java List 使用详解:从入门到精通
java·开发语言·数据结构
秋说1 小时前
【PTA数据结构 | C语言版】在顺序表 list 的第 i 个位置上插入元素 x
c语言·数据结构·list
楼田莉子2 小时前
数据学习之队列
c语言·开发语言·数据结构·学习·算法
秋说2 小时前
【PTA数据结构 | C语言版】返回单链表 list 中第 i 个元素值
c语言·数据结构·list
雾里看山2 小时前
数据结构之队列
数据结构
双叶8363 小时前
(C++)任务管理系统(正式版)(迭代器)(list列表基础教程)(STL基础知识)
c语言·开发语言·数据结构·c++·list
s153353 小时前
数据结构-顺序表-拿硬币
数据结构
嗜好ya4 小时前
LeetCode 560: 和为K的子数组
数据结构·算法·leetcode