【问题标题】:Generate permutations of JavaScript array [duplicate]生成JavaScript数组的排列[重复]
【发布时间】:2016-10-01 11:46:17
【问题描述】:

我在 javascript 中有一个包含 n 个不同元素的数组,我知道有 n 个!订购这些元素的可能方式。我想知道生成该数组所有可能排序的最有效(最快)算法是什么?

我有这个代码:

var swap = function(array, frstElm, scndElm) {

    var temp = array[frstElm];
    array[frstElm] = array[scndElm];
    array[scndElm] = temp;
}

var permutation = function(array, leftIndex, size) {

    var x;

    if(leftIndex === size) {

        temp = "";

        for (var i = 0; i < array.length; i++) {
            temp += array[i] + " ";
        }

        console.log("---------------> " + temp);

    } else {

        for(x = leftIndex; x < size; x++) {
            swap(array, leftIndex, x);
            permutation(array, leftIndex + 1, size);
            swap(array, leftIndex, x);
        }
    }
}

arrCities = ["Sidney", "Melbourne", "Queenstown"];
permutation(arrCities, 0, arrCities.length);

它可以工作,但我想交换每个项目以获取组合在内存方面有点昂贵,我认为这样做的一个好方法是只关注数组的索引并获取数字的所有排列,我想知道是否有一种方法可以计算所有这些而不必切换数组中的元素?我想递归是可能的,我需要帮助才能做到这一点。

例如,如果我有:

arrCities = ["Sidney", "Melbourne", "Queenstown"];

我希望输出是:

[[012],[021],[102],[120],[201],[210]]

或:

[[0,1,2],
 [0,2,1],
 [1,0,2],
 [1,2,0],
 [2,0,1],
 [2,1,0]]

我正在读这个: http://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations

但维基百科从来不善于解释。不是很懂,不得不说我的数学水平不是最好的。

【问题讨论】:

  • 请解释您所说的“最有效”是什么意思。最快的?最低的内存使用率?
  • 没有n!排列,除非您绝对确定数组中的所有 n 个元素彼此不同(或者,更好,可辨别)。如果两个元素无法区分,那么你的 n 就已经少了!排列(事实上,你会有重复排列)。
  • @EvanTrimboli 不一样,我想按索引而不是按元素来做
  • 不太确定有什么不同。用数字替换名字也是同样的问题。
  • @EvanTrimboli 该方法必须将其中的元素切换为数组以实现所有排列,我猜这在速度(和内存)方面太昂贵了,我不擅长数学,但我的逻辑告诉我应该是一种计算范围内所有可能数字的方法,这样做比必须实际重新定位每个元素要快得多

标签: javascript arrays recursion permutation


【解决方案1】:
function permutations(str) {
 return (str.length <= 1) ? [str] :
         Array.from(new Set(
           str.split('')
              .map((char, i) => permutations(str.substr(0, i) + str.substr(i + 1)).map(p => char + p))
              .reduce((r, x) => r.concat(x), [])
         ));
}

【讨论】:

    【解决方案2】:

    这只是为了好玩-我在一个字符串中递归解决

    const perm = a => a.length ? a.reduce((r, v, i) => [ ...r, ...perm([ ...a.slice(0, i), ...a.slice(i + 1) ]).map(x => [ v, ...x ])], []) : [[]]
    

    【讨论】:

    • 计算 11 个元素的排列需要很长时间。
    • 好的,我现在只想说,我喜欢单行。非常感谢您!
    • 很酷但也不可读
    【解决方案3】:

    这个函数,perm(xs),返回给定数组的所有排列:

    function perm(xs) {
      let ret = [];
    
      for (let i = 0; i < xs.length; i = i + 1) {
        let rest = perm(xs.slice(0, i).concat(xs.slice(i + 1)));
    
        if(!rest.length) {
          ret.push([xs[i]])
        } else {
          for(let j = 0; j < rest.length; j = j + 1) {
            ret.push([xs[i]].concat(rest[j]))
          }
        }
      }
      return ret;
    }
    
    console.log(perm([1,2,3]).join("\n"));

    【讨论】:

      【解决方案4】:

      这是我基于le_m的代码的版本:

      function permute(array) {
      	Array.prototype.swap = function (index, otherIndex) {
      		var valueAtIndex = this[index]
      
      		this[index] = this[otherIndex]
      		this[otherIndex] = valueAtIndex
      	}
      
      	var result = [array.slice()]
      
      	, length = array.length
      
      	for (var i = 1, heap = new Array(length).fill(0)
      		; i < length
      	;)
      		if (heap[i] < i) {
      			array.swap(i, i % 2 && heap[i])
      			result.push(array.slice())
      			heap[i]++
      			i = 1
      		} else {
      			heap[i] = 0
      			i++
      		}
      
      	return result
      }
      
      console.log(permute([1, 2, 3]))

      这是我对相同算法的递归 JavaScript 实现:

      Array.prototype.swap = function (index, otherIndex) {
      	var valueAtIndex = this[index]
      
      	this[index] = this[otherIndex]
      	this[otherIndex] = valueAtIndex
      }
      
      Array.prototype.permutation = function permutation(array, n) {
      	array = array || this
      	n = n || array.length
      
      	var result = []
      
      	if (n == 1)
      		result = [array.slice()]
      	else {
      		const nextN = n - 1
      
      		for (var i = 0; i < nextN; i++) {
      			result.push(...permutation(array, nextN))
      			array.swap(Number(!(n % 2)) && i, nextN)
      		}
      
      		result.push(...permutation(array, nextN))
      	}
      
      	return result
      }
      
      console.log([1, 2, 3].permutation())

      【讨论】:

        【解决方案5】:

        使用 Heap 的方法(您可以在您的 Wikipedia 文章链接到的 in this paper 中找到它),您可以生成具有 O(N!) 的运行时复杂度和 O(N) 的空间复杂度的 N 个元素的所有排列。该算法基于交换元素。 AFAIK 这是最快的,没有更快的方法来计算所有排列。

        有关实现和示例,请查看at my recent answer 相关问题"permutations in javascript"

        【讨论】:

        • 有些方法 tath 不会计算所有可能的排列,但会进行非常接近的计算?
        • @DSB 我想我不明白。如果您不想生成所有排列而只想生成一些排列,请查看Lehmer code,它允许您在给定字典排列索引的情况下快速计算单个排列。
        • 使用这个答案 (stackoverflow.com/a/37580979/1647737) 的基本测试比上面的@chacmoolvm 答案快 10 倍
        猜你喜欢
        • 1970-01-01
        • 2014-03-15
        • 1970-01-01
        • 2020-01-12
        • 1970-01-01
        • 1970-01-01
        • 2011-03-07
        相关资源
        最近更新 更多