LeetCode/solutions/322. Coin Change.md
2019-11-23 23:45:42 +08:00

51 lines
2.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# [322. Coin Change](https://leetcode.com/problems/coin-change/)
# 思路
换零钱给定一个钱的价值amount和一些面值假设每个面值的硬币数都是无限的问我们最少能用几个硬币组成给定的价值。
## 思路一
此题很容易想到直接搜索所有可能然后保持一个全局的结果res但是直接搜索很容易超时。因此需要做一些剪枝为了剪枝剪得更狠我们可以先对面值数组coins从大到小
排个序这样做的原因是如果某个amount可以直接被某个面值整除那就可以直接返回整除的结果而不用考虑比这个面值小的面值了。
我们定义一个搜索函数helper传入排好序的coins、面值开始索引start初始为0、当前目标target初始为amount、当前已用硬币数初始为0、全局结果res初始为INT_mAX引用传入:
* 当start超出coins数组的范围直接返回即可
* 当target可以被 coins[start] 整除那么全局res就更新为`min(res, cur + target / coins[start])`然后返回。
* 否则就需要进行递归搜索了此时我们需要采取贪心的策略即从最多可加入硬币coins[start]的数目`target / coins[start]`开始逐渐递减代码中这个次数为i
一旦遇到`cur + i >= res - 1`直接break因为当前的i递归下去最少需要的硬币数`cur + i + 1`不会比res小所以就不用进行搜索了而再循环下去即i--res也不可能比当前res小想想为什么因此也不用再循环下去了。
这个剪枝很关键少了这个剪枝就会超时加上这个剪枝直接击败99%。若不满足这个剪枝条件,那么递归下去就是。
## 思路二
熟悉动态规划的童鞋一眼就可以看出这其实就是个背包问题,先挖个坑,改天对背包问题做个总结。
# 思路
## 思路一
``` C++
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int res = INT_MAX, n = coins.size();
sort(coins.begin(), coins.end(), greater<int>());
helper(coins, 0, amount, 0, res);
return (res == INT_MAX) ? -1 : res;
}
void helper(vector<int>& coins, int start, int target, int cur, int& res) {
if (start >= coins.size()) return;
if (target % coins[start] == 0){
// 能整除的话肯定不用再递归了, 因为coins已从大到小排好序
res = min(res, cur + target / coins[start]);
return;
}
for (int i = target / coins[start]; i >= 0; --i) {
// 满足这个条件就不用搜索也不用循环了
if (cur + i >= res - 1) break;
helper(coins, start + 1, target - i * coins[start], cur + i, res);
}
}
};
```
## 思路二
TODO