力扣-322. 零钱兑换

1.题目介绍

题目地址(322. 零钱兑换 - 力扣(LeetCode))

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

2.题解

2.1 动态规划

思路

这里我们可以发现,我们每次选择一种硬币进行找零,都会从当前状态转移到另一种状态,且每次有且只有选择和不选择两种方式,
由于每种硬币的数量是无限的,我们马上就考虑这是一个完全背包问题。
我们设置dp[i], i代表当前已找零钱总数,dp[i]的值代表达成找零钱i所用的最小钱币数
由于我们要求的是最小值(消耗),所以这里初始化并不能为0,而应该初始化为INT_MAX 或者 amount + 1,
这里建议初始化amount + 1, 如果初始化为INT_MAX,那么就有可能产生由于dp[i - j] + 1导致的越界(这里其实是dp[i-j]根本没有产生相应的组合,所以我们需要加一个判断,判断该组合确实存在!!!)

代码

  • 语言支持:C++

C++ Code:


class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int n = coins.size();
        vector<int> dp(amount + 1, INT_MAX);
        dp[0] = 0;
        for(int i = 1; i <= amount; i++){
            for(int j : coins){
                if(i >= j && dp[i - j] != INT_MAX){
                    dp[i] = min(dp[i], dp[i - j] + 1);
                }  
            }      
        }
        return dp[amount] == INT_MAX? -1 : dp[amount];
    }
};

复杂度分析

令 n 为数组长度。

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(n)\)
posted @ 2024-06-24 00:46  DawnTraveler  阅读(93)  评论(0编辑  收藏  举报