说明
硬币找零问题是给出要找零的钱数,以及可用的硬币面额,找出有多少中找零方法,找到所需的最少的硬币个数
例子
美国有以下面额的硬币:coins = [1,5,10,25]。要找amount = 36美分的零钱,找到所需的最少硬币集合min = [...]。
思路
通过循环coins比较[coins[i],...other] 集合的长度(other可以通过递归基于更小的值求解),取最短的即为最少硬币集合min
代码
let coins = [1, 5, 10, 25];
function minCoin(coins, amount) {
//递归的时候会有很多重复的amount值需要计算,所以这里设置缓存
let cache = {};
function find(value) {
// 当要找的硬币总数为0时,最少的硬币为[]
if (value <= 0) {
return [];
}
// 返回缓存
if (cache[value]) {
return cache[value];
}
// 最少硬币个数(必须保证min是数组,因为有可能下面的递归没找到符合条件的newMin)
let min = [];
// 新的最少硬币个数,和min比较
let newMin;
// 递归的值
let newValue;
for (let i = 0; i < coins.length; i++) {
let coin = coins[i];
// 36-1,-1,-1,-1...最终递归到最小的newValue 1- 1 = 0
newValue = value - coin;
if (newValue >= 0) {
//最终 1-1=0 newMin = []
newMin = find(newValue);
}
// for循环第一轮i=0开始的时候min = [],如果有 newMin的话,直接合并当前的coin 和newValue得到的newMin
// 当min里面有值时,循环再比较的时候,min已经是一个最少硬币的集合,而newMin+coin才是一个集合,所以使用(newMin.length+1 < min.length)比较
// (newMin.length || !newValue)
//如果newMin.length证明剩余值 newValue 可以分解成更小的数组,value可以被分成[coin,...newValue]的组合
//如果!newValue 则剩余值newVlaue===0,可以直接使用[coin]
if(newValue>=0 && (newMin.length+1 < min.length || !min.length)&& (newMin.length || !newValue)) {
min = [coin,...newMin]
}
}
return min
}
return find(amount)
}