排列总和/组合总和Ⅳ
322. 零钱兑换
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -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
解题思路
动态规划
此题coins里面的元素可以重复使用,故为完全背包问题
1.确定dp数组及下标的含义
dp[j] 表示凑成金额为 j 使用硬币最少的数量为dp[j]
2.确定递推公式
dp[j] 可以由dp[j - coins[i]] 得到,若考虑coins[i],那么凑成金额为 j 的最少硬币数量就为dp[j - coins[i]] + 1
而dp[j] 要取所有dp[j] 中的较小者
故递推公式为,dp[j] = Math.min(dp[j], dp[j - coins[i]]+1)
3.初始化dp数组
非排列组合问题,dp[0] = 0,表示凑成总金额为0的硬币数量最少是0
对于非0下标,dp[j]必须初始化为一个最大值,否则再求最小值时会被0覆盖
只有dp[j-coins[i]] 不为最大值时,才进行比较,因为dp[j-coins[i]]为最大值表示没有方案可以凑成j - coins[i]
4.确定遍历顺序
非排列组合问题,先遍历物品后遍历背包或先遍历背包后遍历物品都可以
这里选先遍历物品,后遍历背包,完全背包问题要从小到大遍历背包
代码
1 |
|
- 时间复杂度:$O(n\times m)$,n为coins.length,m为amount
- 空间复杂度:$O(m)$