我试图写一个函数,它做以下工作:

以一个整数数组作为参数(例如[1,2,3,4]) 创建一个包含[1,2,3,4]的所有可能排列的数组,每个排列的长度为4

下面的函数(我在网上找到的)通过接受一个字符串作为参数,并返回该字符串的所有排列来实现这一点

我不知道如何修改它,使它与整数数组一起工作,(我认为这与一些方法在字符串上的工作方式不同于在整数上的工作方式有关,但我不确定…)

let permArr = [];
let usedChars = [];

function permute(input) {
    const chars = input.split("");
    for (let i = 0; i < chars.length; i++) {
        const ch = chars.splice(i, 1);
        usedChars.push(ch);
        if (chars.length === 0) {
            permArr[permArr.length] = usedChars.join("");
        }
        permute(chars.join(""));
        chars.splice(i, 0, ch);
        usedChars.pop();
    }
    return permArr
};

注意:我希望函数返回整数数组,而不是字符串数组。

我真的需要解决方案是在JavaScript。我已经知道如何在python中做到这一点


当前回答

perm = x => x[0] ?  x.reduce((a, n) => (perm(x.filter(m => m!=n)).forEach(y => a.push([n,...y])), a), []): [[]]

其他回答

我写了一篇文章来演示如何在JavaScript中排列数组。下面是执行此操作的代码。

var count=0;
function permute(pre,cur){ 
    var len=cur.length;
    for(var i=0;i<len;i++){
        var p=clone(pre);
        var c=clone(cur);
        p.push(cur[i]);
        remove(c,cur[i]);
        if(len>1){
            permute(p,c);
        }else{
            print(p);
            count++;
        }
    }
}
function print(arr){
    var len=arr.length;
    for(var i=0;i<len;i++){
        document.write(arr[i]+" ");
    }
    document.write("<br />");
}
function remove(arr,item){
    if(contains(arr,item)){
        var len=arr.length;
        for(var i = len-1; i >= 0; i--){ // STEP 1
            if(arr[i] == item){             // STEP 2
                arr.splice(i,1);              // STEP 3
            }
        }
    }
}
function contains(arr,value){
    for(var i=0;i<arr.length;i++){
        if(arr[i]==value){
            return true;
        }
    }
    return false;
}
function clone(arr){
    var a=new Array();
    var len=arr.length;
    for(var i=0;i<len;i++){
        a.push(arr[i]);
    }
    return a;
}

就叫

permute([], [1,2,3,4])

将工作。关于这是如何工作的详细信息,请参考那篇文章中的解释。

这是一个有趣的任务这是我的贡献。它非常简单和快速。如果有兴趣,请耐心阅读。

如果你想快速完成这项工作,你肯定得让自己进入动态编程。这意味着您应该忘记递归方法。那是肯定的……

好的,le_m的代码,它使用了Heap的方法,似乎是目前为止最快的。我的算法还没有名字,我不知道它是否已经实现了,但它非常简单和快速。与所有动态规划方法一样,我们将从最简单的问题开始,然后走向最终的结果。

假设我们有一个数组a =[1,2,3],我们将从它开始

r = [[1]]; // result
t = [];    // interim result

然后遵循以下三个步骤;

对于r (result)数组的每一项,我们将添加输入数组的下一项。 我们将旋转每个项的长度多次,并将每个实例存储在中间结果数组t中(好吧,除了第一个不浪费时间旋转0)。 一旦我们处理完r的所有项,中间数组t应该保存下一层的结果,因此我们使r = t;T = [];一直到输入数组a的长度。

下面是我们的步骤;

r array   | push next item to |  get length many rotations
          |  each sub array   |       of each subarray
-----------------------------------------------------------
[[1]]     |     [[1,2]]       |     [[1,2],[2,1]]
----------|-------------------|----------------------------
[[1,2],   |     [[1,2,3],     |     [[1,2,3],[2,3,1],[3,1,2],
 [2,1]]   |      [2,1,3]]     |      [2,1,3],[1,3,2],[3,2,1]]
----------|-------------------|----------------------------
previous t|                   |
-----------------------------------------------------------

这就是代码

function perm(a){ var r = [[a[0]]], t = [], s = []; if (a.length <= 1) return a; for (var i = 1, la = a.length; i < la; i++){ for (var j = 0, lr = r.length; j < lr; j++){ r[j].push(a[i]); t.push(r[j]); for(var k = 1, lrj = r[j].length; k < lrj; k++){ for (var l = 0; l < lrj; l++) s[l] = r[j][(k+l)%lrj]; t[t.length] = s; s = []; } } r = t; t = []; } return r; } var arr = [0,1,2,4,5]; console.log("The length of the permutation is:",perm(arr).length); console.time("Permutation test"); for (var z = 0; z < 2000; z++) perm(arr); console.timeEnd("Permutation test");

在多次测试中,我已经看到它在25~35ms内解决了[0,1,2,3,4]的120个排列2000次。

下面是递归函数=> https://recursion.vercel.app/的可视化

 var permute = function (nums) {
  let answer = [];

  var permuter = function (arr, permutation = []) {
    if (arr.length === 0) {
      return answer.push(permutation);
    } else {
      for (let i = 0; i < arr.length; i++) {
        let currentArr = arr.slice();
        let next = currentArr.splice(i, 1);
        permuter(currentArr, permutation.concat(next)); ///we use concat because splice returns an array.
      }
    }
  };

  permuter(nums);

  return answer;
};

const permutations = array => { let permut = []; helperFunction(0, array, permut); return permut; }; const helperFunction = (i, array, permut) => { if (i === array.length - 1) { permut.push(array.slice()); } else { for (let j = i; j < array.length; j++) { swapElements(i, j, array); helperFunction(i + 1, array, permut); swapElements(i, j, array); } } }; function swapElements(a, b, array) { let temp = array[a]; array[a] = array[b]; array[b] = temp; } console.log(permutations([1, 2, 3]));

对这个问题的大多数回答都使用昂贵的操作,如连续插入和删除数组中的项,或重复复制数组。

相反,这是典型的回溯解决方案:

function permute(arr) {
  var results = [],
      l = arr.length,
      used = Array(l), // Array of bools. Keeps track of used items
      data = Array(l); // Stores items of the current permutation
  (function backtracking(pos) {
    if(pos == l) return results.push(data.slice());
    for(var i=0; i<l; ++i) if(!used[i]) { // Iterate unused items
      used[i] = true;      // Mark item as used
      data[pos] = arr[i];  // Assign item at the current position
      backtracking(pos+1); // Recursive call
      used[i] = false;     // Mark item as not used
    }
  })(0);
  return results;
}
permute([1,2,3,4]); // [  [1,2,3,4], [1,2,4,3], /* ... , */ [4,3,2,1]  ]

由于结果数组将非常大,因此逐个迭代结果而不是同时分配所有数据可能是一个好主意。在ES6中,这可以通过生成器来完成:

function permute(arr) {
  var l = arr.length,
      used = Array(l),
      data = Array(l);
  return function* backtracking(pos) {
    if(pos == l) yield data.slice();
    else for(var i=0; i<l; ++i) if(!used[i]) {
      used[i] = true;
      data[pos] = arr[i];
      yield* backtracking(pos+1);
      used[i] = false;
    }
  }(0);
}
var p = permute([1,2,3,4]);
p.next(); // {value: [1,2,3,4], done: false}
p.next(); // {value: [1,2,4,3], done: false}
// ...
p.next(); // {value: [4,3,2,1], done: false}
p.next(); // {value: undefined, done: true}