我正在尝试编写一个将金额转换为指定数量的硬币的函数。为此我自己调用一个函数(我认为这是递归编程?)。我有两个问题。
当我在else
语句的if
部分调用该函数时,我收到错误消息。 “超出最大调用堆栈大小”?不确定为什么这是因为上面的调用是相同的,并且在第二次调用被注释掉时工作正常。
此外,当第二个调用被注释掉并且函数运行时,变量total
应该在每次调用时增加1。但是它没有超过1.我认为这可能是因为每次调用时变量都在顶部重置为0。但是,remainder
变量也设置为0,每次都会减小其值。
有人能解释这里发生了什么吗?这个问题最好如何解决?
谢谢
function amountCoins(amt, coins) {
var remainder = 0;
total = 0;
if(amt >= coins[0]) {
total += 1;
remainder = (amt - coins[0]);
return amountCoins(remainder, coins);
} else {
coins.shift();
//return amountCoins(remainder,coins);
}
alert(total);
}
amountCoins(121,[20,15,6,1]);
答案 0 :(得分:1)
您可以使用.reduce()
作为替代方案。
我们并不需要简单数学可以处理它的循环。
var total = [20,15,6,1].reduce(function(obj, denomination) {
return {
total: obj.total + Math.floor(obj.amount / denomination),
amount: obj.amount % denomination
};
}, {amount:121, total:0}).total;
或迭代数组。
var arr = [20,15,6,1], amount = 121, total = 0;
for (var i = 0; i < arr.length; ++i) {
total += Math.floor(amount / arr[i]);
amount %= arr[i];
}
答案 1 :(得分:0)
如果我是你,我会使用常规for
循环:
var amt = 121;
var coins = [20, 15, 6, 1];
var coinsUsed = {};
var totalCoins = 0;
for (var i = 0; i < coins.length; i++) {
if (coins[i] <= amt) {
coinsUsed[coins[i]] = Math.floor(amt / coins[i]);
amt -= coinsUsed[coins[i]] * coins[i];
totalCoins += coinsUsed[coins[i]];
} else {
coinsUsed[coins[i]] = 0;
}
}
console.log(coinsUsed, totalCoins);
输出:
Object {
1: 1,
6: 0,
15: 0,
20: 6
}
7
答案 2 :(得分:0)
问题是您的算法永远不会结束。每个递归函数都必须有一个结束,否则会产生堆栈溢出(xD),因为递归调用存储在堆栈中。
这将是一个解决方案:
function amountCoins(amt, coins, total) {
var remainder = 0;
total = total || 0; //Default value 0 (for the first call)
if(coins.length == 0) return total; //This is the ending condition (no coins)
if(amt >= coins[0]) {
total += 1;
remainder = (amt - coins[0]);
return amountCoins(remainder, coins, total);
} else {
coins.shift();
return amountCoins(remainder, coins, total);
}
}
var coins = amountCoins(121,[20,15,6,1]); //Returns: 6
alert(coins);
正如您所看到的,我将total
变成了一个参数,因此我们可以将其存储在来电之中。
希望这会有所帮助。干杯
答案 3 :(得分:0)
我认为这就是你要做的事情:
function amountCoins(amt, coins) {
var remainder = 0;
if(coins.length == 0) {
return 0;
} else if(amt >= coins[0]) {
remainder = (amt - coins[0]);
return amountCoins(remainder, coins)+1;
} else {
coins.shift();
return amountCoins(remainder,coins);
}
}
var total = amountCoins(121,[20,15,6,1]);
alert(total)
这里有一些事情
递归算法需要终止条件。即。当函数递归调用自身时,它应该在某个时刻停止链。如果没有,程序将耗尽内存以容纳链中的所有调用。因为这是一个潜在的危险情况,像javascript这样的编程语言限制了递归调用的深度。这就是Maximum call stack size exceeded
错误的含义。
在您的程序中,从逻辑上讲,终止条件是我们的硬币耗尽。所以a
coins.length == 0
检查返回0
总计(反过来构成向上链)将解决问题
通常在递归算法中,结果向后传递,在调用链上向上传递,而不是存储在外部变量中。因此递增的总值用返回语句表示,如return amountCoins(remainder, coins)+1;
最后,使用for循环可以很容易地实现这个问题。尝试通过展开递归调用链来思考,你将找到一个循环解决方案。
答案 4 :(得分:0)
对原始代码的此更正将起作用:
function amountCoins(amt, coins, total) {
total = total || 0;
if (amt === 0) return total;
// throw out all the coins that are too big
while (amt < coins[0]) coins.shift();
// use the largest coin possible, then recurse
total += 1;
remainder = amt - coins[0];
return amountCoins(remainder, coins, total);
}
alert(amountCoins(121,[20,15,6,1])); // alerts 7
它具有避免不必要的if ... else
语句的优点,并且逻辑更清晰imo
答案 5 :(得分:0)
您不仅要在没有剩余硬币的情况下返还总数,而且如果最后一个硬币的值大于剩余值,则必须返回总数:
function amountCoins(amt, coins, total) {
total = total || 0;
if (coins.length == 0 || (amt < coins[0] && coins.length == 1)) return total;
if (amt >= coins[0]) {
total += 1;
remainder = (amt - coins[0]);
return amountCoins(amt - coins[0], coins, total);
} else {
coins.shift();
return amountCoins(remainder, coins, total);
}
}