力扣-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)\)