JS: How to create an array containing permutations of a sequence 0 to n in which adjacent numbers must have a difference greater than 1?

孤者浪人 提交于 2021-01-28 07:27:32

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!