Требование: Алгоритм для генерации всех возможных комбинаций набора без дубликатов или рекурсивного вызова функции для возврата результатов.
Большинство, если не все ответы, предоставленные при перестановках в JavaScript? рекурсивно вызывать функцию из цикла или другую функцию для возврата результатов.
Пример рекурсивного вызова функции в цикле
function p(a, b, res) {
var b = b || [], res = res || [], len = a.length;
if (!len)
res.push(b)
else
for (var i = 0; i < len
// recursive call to 'p' here
; p(a.slice(0, i).concat(a.slice(i + 1, len)), b.concat(a[i]), res)
, i++
);
return res
}
p(["a", "b", "c"]);
Текущий Вопрос пытается создать данную перестановку в линейном процессе, опираясь на предыдущую перестановку.
Например, учитывая массив
var arr = ["a", "b", "c"];
определить общее количество возможных перестановок
for (var len = 1, i = k = arr.length; len < i ; k *= len++);
k
должно возвращать 6
или общее количество возможных перестановок arr
["a", "b", "c"]
С общим количеством отдельных перестановок, определенных для набора, результирующий массив, который будет содержать все шесть перестановок, может быть создан и заполнен с использованием Array.prototype.slice()
, Array.prototype.concat()
и Array.prototype.reverse()
var res = new Array(new Array(k));
res[0] = arr;
res[1] = res[0].slice(0,1).concat(res[0].slice(-2).reverse());
res[2] = res[1].slice(-1).concat(res[1].slice(0,2));
res[3] = res[2].slice(0,1).concat(res[2].slice(-2).reverse());
res[4] = res[3].slice(-2).concat(res[3].slice(0,1));
res[5] = res[4].slice(0,1).concat(res[4].slice(-2).reverse());
Попытка воспроизвести результаты на основе шаблона, отображенного на графике для алгоритма упорядоченной лексикографической перестановки, на основе одного из них, опубликованного в Практических алгоритмах в C++ в разделе Расчет перестановок и вопросов о собеседовании.
Кажется, есть шаблон, который можно расширить, если, например, входной набор
["a", "b", "c", "d", "e"]
где можно ожидать 120 перестановок.
Пример попытки заполнения массива, опираясь только на предыдущую перестановку
// returns duplicate entries at 'j'
var arr = ["a", "b", "c", "d", "e"], j = [];
var i = k = arr.length;
arr.forEach(function(a, b, array) {
if (b > 1) {
k *= b;
if (b === i -1) {
for (var q = 0;j.length < k;q++) {
if (q === 0) {
j[q] = array;
} else {
j[q] = !(q % i)
? array.slice(q % i).reverse().concat(array.slice(0, q % i))
: array.slice(q % i).concat(array.slice(0, q % i));
}
}
}
}
})
однако еще не удалось внести необходимые корректировки в параметры для .slice()
, .concat()
, .reverse()
при значениях выше js
чтобы перейти от одной перестановки к следующей; используя только предыдущую запись массива в res
для определения текущей перестановки, без использования рекурсии.
Заметил четный, нечетный баланс вызовов и попытался использовать оператор %
modulus и входной массив .length
для вызова .reverse()
или нет в ["a", "b", "c", "d", "e"]
массив, хотя и не дал результатов без повторяющихся записей.
Ожидаемый результат состоит в том, что вышеуказанный шаблон может быть сокращен до двух строк, вызываемых последовательно на протяжении всего процесса, пока все перестановки не завершены, заполнены res
; по одному на каждый вызов .reverse()
, вызов без .reverse()
; например, после заполнения res[0]
// odd , how to adjust '.slice()' , '.concat()' parameters
// for array of unknown 'n' '.length' ?
res[i] = res[i - 1].slice(0,1).concat(res[i - 1].slice(-2).reverse());
// even
res[i] = res[1 - 1].slice(-1).concat(res[i - 1].slice(0,2));
Вопрос: Какие корректировки к вышеуказанному шаблону необходимы, в частности параметры или индекс, переданные .slice()
, .concat()
чтобы произвести все возможные перестановки данного набора без использования рекурсивного вызова текущей обрабатывающей функции?
var arr = ["a", "b", "c"];
for (var len = 1, i = k = arr.length; len < i; k *= len++);
var res = new Array(new Array(k));
res[0] = arr;
res[1] = res[0].slice(0, 1).concat(res[0].slice(-2).reverse());
res[2] = res[1].slice(-1).concat(res[1].slice(0, 2));
res[3] = res[2].slice(0, 1).concat(res[2].slice(-2).reverse());
res[4] = res[3].slice(-2).concat(res[3].slice(0, 1));
res[5] = res[4].slice(0, 1).concat(res[4].slice(-2).reverse());
console.log(res);