问题
Just to elaborate on the question asked. Given that you have a sequence from 0 to n (0,1,2, ... n-1,n). I want to return an array that contains all the possible permutations that fulfill the condition that adjacent numbers must have a difference greater than 1. For example, given the sequence (0,1,2,3), the only valid permutations would be (1,3,0,2) and (2,0,3,1).
I actually already have a working function.
function validSequences(n) {
let all = [],
baseSequence = [],
startingValue = 0,
sequenceLastIndex = 0;
for (let x=0; x<n; x++) {
baseSequence.push(x);
}
while (startingValue < n) {
while (sequenceLastIndex < (n-1)) {
if (sequenceLastIndex == 0) {
let nextPossibleValues = baseSequence.filter((i) => {
return Math.abs(startingValue - i) > 1;
});
nextPossibleValues.forEach((value) => {
all.push([startingValue, value]);
});
} else {
all.forEach((sequence) => {
if (sequence[0] == startingValue) {
let nextPossibleValues = baseSequence.filter((i) => {
return Math.abs(sequence[sequenceLastIndex] - i) > 1 && !sequence.includes(i);
});
if (nextPossibleValues.length == 0) {
all = all.filter((keep) => {
return keep !== sequence;
});
} else {
nextPossibleValues.forEach((value) => {
let copy = [...sequence];
copy.push(value);
all.push(copy);
});
}
all = all.filter((keep) => {
return keep[0] !== startingValue || keep.length == (sequenceLastIndex + 2);
});
}
});
}
sequenceLastIndex++;
}
sequenceLastIndex = 0;
startingValue++;
}
return all;
}
The above function will produce instantaneous results for sequences up to 0-7. Anything above that will take a ridiculous amount of time. Can anyone come up with a solution that can handle longer sequences, or one that is more efficient/elegant than the one I have currently?
回答1:
You'll definitely need something more elegant to make the code maintainable. I'd recommend to start with a normal recursive solution, maybe a fancy (and efficient) generator function:
function* permutations(array, i) {
if (i >= array.length)
yield array;
else
for (let j=i; j<array.length; j++)
yield* permutations([
...array.slice(0, i),
array[j],
...array.slice(i, j),
...array.slice(j+1)
], i+1);
}
Array.from(permutations(['a', 'b', 'c', 'd'], 0))
Now all you need to do is add the condition for neighbouring elements:
function* permutations(array, i) {
if (i >= array.length)
yield array;
else
for (let j=i; j<array.length; j++)
if (i == 0 || Math.abs(array[i-1] - array[j]) > 1)
yield* permutations([
...array.slice(0, i),
array[j],
...array.slice(i, j),
...array.slice(j+1)
], i+1);
}
Array.from(permutations([0, 1, 2, 3], 0))
Anything above sequences up to 0-7 will take a ridiculous amount of time
That's rather normal. There are many, many permutations for array of that size, and your condition only filters out a few of them. Here's a quick table:
length | number of solutions
-------+---------------------
0 | 1
1 | 1
2 | 0
3 | 0
4 | 2
5 | 14
6 | 90
7 | 646
8 | 5242
9 | 47622
10 | 479306
…aka OEIS A002464 :-)
来源:https://stackoverflow.com/questions/57083786/js-how-to-create-an-array-containing-permutations-of-a-sequence-0-to-n-in-which