给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
典型的DP问题,自下而上和自上而下都可以解决,使用DFS配合恰当的减枝策略也效果拔群。
具体思路讲解:题解
嘴一句:如果换成求组合的个数则直接转换为数论中无线多重集的组合个数的问题,直接套公式即可。
DFS
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31class Solution { public: int ans = INT_MAX; int coinChange(vector<int>& coins, int amount) { sort(coins.begin(), coins.end()); dfs(coins, coins.size() - 1, amount, 0); return ans == INT_MAX ? -1 : ans; } void dfs(vector<int>& coins, int index, int amount, int cnt) { if (index < 0){ return; } for (int c = amount / coins[index]; c >= 0; c--){ //大面值从多到少 int remains = amount - c * coins[index]; int tempcnt = cnt + c; if (remains == 0){ //已经完成了一种分配方案 this->ans = min(this->ans, tempcnt); break; } if (tempcnt >= ans){ break; } dfs(coins, index - 1, remains, tempcnt); } } };
自上而下DP
自上而下的DP一般会造成递归调用中的重复计算,所以一般需要加辅助内存来保存计算结果,如下面的代码中使用了一个辅助vector作为记忆数组。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28class Solution { public: vector<int> count; //存储组成金额S所需的最少硬币数量。 int dp(vector<int> &coins, int rem) { if (rem < 0) return -1; if (rem == 0) return 0; //动态规划记忆数组; if (count[rem - 1] != 0) return count[rem - 1]; int Min = INT_MAX; for (int coin : coins){ int res = dp(coins, rem - coin); if (res >= 0 && res < Min){ Min = res + 1; } } count[rem - 1] = Min == INT_MAX ? -1 : Min; return count[rem - 1]; } int coinChange(vector<int>& coins, int amount) { if (amount < 1) return 0; count.resize(amount); return dp(coins, amount); } };
自下而上DP
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class Solution { public: int coinChange(vector<int>& coins, int amount) { int Max = amount + 1; vector<int> dp(amount + 1, Max); dp[0] = 0; for (int i = 1; i <= amount; ++i){ for (int j = 0; j < (int)coins.size(); ++j){ if (coins[j] <= i){ dp[i] = min(dp[i], dp[i - coins[j]] + 1); } } } //因为是用Max初始化的,所以如果大于amount就说明没有改变,无法组成指定的金额。 return dp[amount] > amount ? -1 : dp[amount]; } };
最后
以上就是畅快黄豆最近收集整理的关于每日一题:零钱兑换的全部内容,更多相关每日一题内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复