NaN在递归for循环中

时间:2020-07-02 16:58:30

标签: javascript recursion

我试图理解我为一个问题找到的解决方案:“您获得了不同面额的硬币和总金额。编写一个函数来计算组成该金额的组合数量。您可能会假设每种硬币都有无限数量。”

我的问题是,如果我运行带有change(3,[2])的函数,为什么它会吐出0。我在理解单个递归调用currentCoin之后变得未定义以及随后何时执行程序时遇到了麻烦到达该调用中的for循环,它不会再使用total += change(amount - 0 * undefined, coins.slice(0, -1))来调用change函数。为什么在空数组上使用change(NaN,[])coins.slice(0,-1)进行无限递归调用时,它不会崩溃。似乎忽略了for循环。

我误解了for循环的工作原理吗?

var change = function(amount, coins) {
    if(amount == 0) return 1; 
    
    let currentCoin = coins[coins.length - 1];
    let total = 0;

    for(let qty = 0; qty * currentCoin <= amount; qty++){
        total += change(amount - qty * currentCoin, coins.slice(0, -1))
    }

    return total;
};

console.log(change(3,[2]))

4 个答案:

答案 0 :(得分:0)

不会崩溃,因为与数字相比NaN都是错误的... NaN <数字或NaN>数字等等产生假的...所以

qty * currentCoin <= amount

评估为假,将从for中退出。

因此,如果您需要检查NaN,则必须在for之前

let totalCoin = qty * currentCoin;
let check = isNaN(totalCoin);
if(check) {
  // return you sentinel value;
}

答案 1 :(得分:0)

var change = function(amount, coins) {
    if(amount == 0) return 1; 
    
    let currentCoin = coins[coins.length - 1]; // firstpass 1-1 = 0, second pas 0-1=-1 => coins[-1] = undefined 
    let total = 0;
                   // this will 0*0<=3, second pass 0*undefined => null which is false hence never execute      
    for(let qty = 0; qty * currentCoin <= amount; qty++){
        total += change(amount - qty * currentCoin, coins.slice(0, -1))
    }

    return total;
};

console.log(change(3,[2]))

第二遍时,coins.length = 0,然后

let currentCoin = coins[0 - 1]; // = undefined 

稍后在for循环中,您将得到0 * undefined(qty * currentCoin),这将导致NaN不是数字

答案 2 :(得分:0)

在这种情况下,无需递归。可以使用自底向上的动态编程方法。令ways[i]表示使用给定硬币获得i美元的方式,而coins[i]代表第i个硬币的价值。然后,ways[i]是所有ways[i - coins[j]]的所有j从1到硬币数量的总和。

var change = function(amount, coins) {
    const ways = Array(amount + 1);
    ways[0] = 1;
    for(const coin of coins){
      for(let i = coin; i <= amount; i++){
        ways[i] = (ways[i] ?? 0) + ways[i - coin] ?? 0;
      }
    }
    return ways[amount];
};
console.log(change(5,[1,2,3,4,5]))

答案 3 :(得分:0)

这里发生了几件事。

首先是coins[coins.length - 1]的行为。在Javascript中,当您在列表中不存在的索引中访问列表的元素时,索引器将返回undefined而不是用IndexOutOfBoundsException之类的东西崩溃。

第二个是qty * currentCoin <= amount。在currentCoin未定义的情况下(由于上述原因),qty * currentCoin将是NaN。在Javascript中,NaN与另一个数字的任何比较在设计上都会返回false。 (例如NaN <= anything为假)。

将所有内容放在一起,您会发现在第一次递归中,coins数组将为空,从而使currentCoin为NaN。这将导致qty * currentCoin <= currentAmount为假,从而导致循环短路(因此slice永远不会在空列表中被调用)。由于循环永远不会执行,因此total仍为0,这是返回的值。这一直持续到qty * currentCoin <= amount在最外层递归中变为true为止,并且该循环以total仍等于0退出(因为它只添加了0)。

如果您在函数的关键位置插入console.log调用,则会更清楚地了解正在发生的事情:

var change = function(amount, coins) {
  console.log(amount, coins);
  if(amount == 0) return 1; 

  let currentCoin = coins[coins.length - 1];
  console.log(':', currentCoin, amount);
  let total = 0;

  for(let qty = 0; qty * currentCoin <= amount; qty++){
    total += change(amount - qty * currentCoin, coins.slice(0, -1))
    console.log('=', total);
  }

  console.log('recdone');
  return total;
};

console.log(change(3,[2]))