我花了一整天时间(最后)在周五的一个入学申请实践中围绕一个排列算法。 Heap的算法对我来说似乎最简单和优雅。
这是一个例子:http://en.wikipedia.org/wiki/Heap%27s_algorithm
function permutationArr(num) {
var str = num.toString();
var arr = str.split('');
var permutations = [];
function getPerm(arr,n){
var localArr = arr.slice(0);
var i;
var swap;
var temp;
if(n==1){
permutations.push(localArr.toString());
return;
}
for(i=0;i<n;i++){
getPerm(localArr,n-1);
swap = (n%2 ? i: 0);
temp = localArr[swap];
localArr[swap] = localArr[n-1];
localArr[n-1] = temp;
}
}
getPerm(arr,arr.length);
console.log(permutations);
return;
}
permutationArr(1234);
最终排列数组的日志在这里:
["1,2,3,4", "1,3,2,4", "4,2,3,1", "4,3,2,1", "4,1,3,2", "4,3,1,2", "1,,3,4,2", "1,3,,4,2", "4,,3,1,2", "4,3,,1,2", "4,1,3,,2", "4,3,1,,2", "1,2,3,4,", "1,3,2,4,", "4,2,3,1,", "4,3,2,1,", "4,1,3,2,", "4,3,1,2,", "1,,3,4,2", "1,3,,4,2", "4,,3,1,2", "4,3,,1,2", "4,1,3,,2", "4,3,1,,2"]
它获得了前12个排列,然后一个','被神秘地添加,并且前12个排列被重复。我很难过。
编辑:上面是更新的代码,考虑到评论所说的帮助。仍然只有一半的排列。
答案 0 :(得分:10)
除了使用你应该使用n
的索引n - 1
之外,问题在于你假设必须在调用之间复制数组(即不可变行为)。
该算法假定数组在每个递归步骤中始终相同,因此,由于JavaScript处理范围的方式,您可以大大简化代码:
function permutationArr(num)
{
var arr = (num + '').split(''),
permutations = [];
function swap(a, b)
{
var tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
function generate(n) {
if (n == 1) {
permutations.push(arr.join());
} else {
for (var i = 0; i != n; ++i) {
generate(n - 1);
swap(n % 2 ? 0 : i, n - 1);
}
}
}
generate(arr.length);
return permutations;
}
console.log(permutationArr(1234));
&#13;
["1,2,3,4", "2,1,3,4", "3,1,2,4", "1,3,2,4", "2,3,1,4", "3,2,1,4", "4,2,3,1",
"2,4,3,1", "3,4,2,1", "4,3,2,1", "2,3,4,1", "3,2,4,1", "4,1,3,2", "1,4,3,2",
"3,4,1,2", "4,3,1,2", "1,3,4,2", "3,1,4,2", "4,1,2,3", "1,4,2,3", "2,4,1,3",
"4,2,1,3", "1,2,4,3", "2,1,4,3"]
答案 1 :(得分:10)
自2018年1月以来更新的答案: 接受的答案绝对正确,但从那时起js已经发展。随之而来的是一些新功能,其中2个可以帮助解决这个问题。
cmake_minimum_required(VERSION 3.5)
project(Image_processing)
set(CMAKE_CXX_STANDARD 14)
find_package(OpenCV REQUIRED)
#include_directories(/home/user/opencv/build)
add_executable(Image_processing main.cpp)
target_link_libraries(Image_processing ${OpenCV_LIBS})
let [a, b] = [1, 2]; // a=1, b=2
有了这个,我们可以像这样实现Heap's algorithm:
function *foo {
yield 1;
yield 2;
yield 3;
}
const bar = foo();
bar.next(); // 1
bar.next(); // 2
bar.next(); // 3
function *heaps(arr, n) {
if (n === undefined) n = arr.length;
if (n <= 1) yield arr;
else {
for (let i = 0; i < n - 1; i++) {
yield *heaps(arr, n-1);
if (n % 2 === 0) [arr[n-1], arr[i]] = [arr[i], arr[n-1]];
else [arr[n-1], arr[0]] = [arr[0], arr[n-1]];
}
yield *heaps(arr, n-1);
}
}
for (let a of heaps([1, 2, 3, 4])) {
console.log(`[${a.join(', ')}]`);
}
答案 2 :(得分:2)
我分享了这个答案,因为我想展示一下旧javascript中狭窄的功能集如何也可以简洁明了。编写在最古老的javascript引擎中运行的代码并轻松移植到其他语言(例如C)有时是一个优点。在这种情况下,使用回调效果很好,因为它使函数可用于更广泛的用途,例如减少创建排列时将其排列为唯一的排列。
非常短的变量名可以使算法更清晰。
function swap(a, i, j) { var t = a[i]; a[i] = a[j]; a[j] = t }
function perm(arr, n, cb) {
if (n === 1) {
cb(arr);
} else {
for (var i = 0; i < n; i++) {
perm(arr, n - 1, cb);
swap(arr, n % 2 ? 0 : i, n - 1);
}
}
}
perm([1,2,3,4], 4, function (p) {
console.log(p);
})
这对于测试非常有用,因此我将其提供给我使用的数据驱动测试工具: