【问题标题】:Javascript recursive number permutationsJavascript递归数字排列
【发布时间】:2015-10-14 18:35:23
【问题描述】:

当我输入这个函数 85 时,它只返回 85。我不明白为什么不以 5 作为第一个数字再次递归调用自己。

console.log(PermutationStep(85));

function PermutationStep(num) { 
  var perms = [];

  rec(String(num), String(num).length, [], '');
  return perms;

  function rec(num, numLength, used, currPerm) {
    console.log(currPerm);
    if (currPerm.length === numLength) {
      perms.push(num);
    }
    for (var j=0; j<numLength; j++) {
      if (used[j]) continue;
      else {
        used[j]=true;
        rec(num, numLength, used, currPerm+num[j]);
      }
    }
  }
}

【问题讨论】:

  • 你需要在 for-loop 中的 rec 完成后将 used[j] 设置回 false

标签: javascript recursion permutation


【解决方案1】:
  1. 当达到长度时,您应该推送currPerm 而不是num

  2. used[j] 在被跟踪后再次可用。

  3. 它可能会产生重复的结果,如885,你需要确保它不跟踪相同的值。

console.log(PermutationStep(85));
console.log(PermutationStep(885));

function PermutationStep(num) { 
  var perms = [];
  
  // Convert number to char array.
  var str = ('' + num).split('');
  var length = str.length;
  // sort by alphabetical order.
  str.sort(function(a, b) {
    return a - b;
  });

  // Create used map.
  var used = str.map(function() {
    return false;
  });

  rec(str, '');
  return perms;

  // Not that javascript can reference value from outer function scope,
  // So we don't need to pass length and used each time, like you treat with perms.
  function rec(num, currPerm) {
    console.log(currPerm);
    if (currPerm.length === length) {
      // Put the constructed string here, not num
      perms.push(currPerm);
    }
    var prev = null, ch;
    for (var j = 0; j < length; j++) {
      if (used[j]) {
        continue;
      }
      ch = str[j];
      if (prev === ch) { 
        // If current char is same wih previous, there's more than 2 ch in the string,
        // So we need to skip to prevent duplicate result.
        continue;
      }
      used[j] = true;
      rec(num, currPerm + ch);
      // Make the number usable again.
      used[j]=false;
      prev = ch;
    }
  }
}

【讨论】:

  • 如果最初使用的是 [],那么在第一次递归调用之后它将是 [true] 并且 j =1。 used[1] 为假,为什么不进行第二次递归调用?
  • 因为你要检查第二个数字,也就是第二个嵌套的rec,它会将used[1]标记为true。所以当你回到第一个rec,循环到j = 1,使用的是[true, true],所以跳过了。
  • 当你传递rec(num, numLength, used, currPerm+num[j]);时,注意javascript会将指向used的引用指针传递给rec,所以如果你在嵌套函数中修改used,它也会修改外部使用它的函数。
  • 即使你使用used.slice(0)传递一个用于嵌套rec的副本,你仍然需要在嵌套rec完成后将其设置回false,例如,在index 0之后的结果是 done(85),used[true, undefined] 然后在 j = 1,如果你没有将 used[0] 设置回 false,你会将 [true, true] 传递给嵌套,这将什么都不生成,因为它认为 all used 都是真的。
  • 我刚刚用 used.slice(0) 试了一下,它可以在没有设置回 false 的情况下工作
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-13
  • 1970-01-01
  • 1970-01-01
  • 2014-08-19
  • 2017-02-17
  • 2011-06-18
相关资源
最近更新 更多