【问题标题】: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?JS:如何创建一个数组,其中包含序列 0 到 n 的排列,其中相邻数字的差必须大于 1?
【发布时间】:2019-07-17 20:40:42
【问题描述】:

只是为了详细说明所提出的问题。假设您有一个从 0 到 n (0,1,2, ... n-1,n) 的序列。我想返回一个数组,其中包含满足相邻数字的差必须大于 1 的条件的所有可能排列。例如,给定序列 (0,1,2,3),唯一有效的排列是 ( 1,3,0,2) 和 (2,0,3,1)。

其实我已经有了一个工作函数。

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;
}

上述函数将产生最多 0-7 的序列的瞬时结果。任何高于此的时间都将花费大量时间。谁能想出一个可以处理更长序列的解决方案,或者比我目前拥有的更高效/优雅的解决方案?

【问题讨论】:

  • all 的循环期间修改all 是一个非常糟糕的主意。
  • 生成的排列顺序重要吗?
  • 既然你提到了它,我肯定明白为什么在循环遍历数组时更改数组是一个坏主意,而且顺序无关紧要。

标签: javascript dynamic-arrays


【解决方案1】:

您肯定需要更优雅的东西来使代码可维护。我建议从一个普通的递归解决方案开始,也许是一个花哨(和高效)的生成器函数:

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))

现在您需要做的就是为相邻元素添加条件:

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))

任何高于 0-7 的序列都将花费大量时间

这很正常。这种大小的数组有很多很多排列,而您的条件只过滤掉其中的几个。这是一个快速表:

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

…又名OEIS A002464 :-)

【讨论】:

  • 我正要链接到那个!哈。
猜你喜欢
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 2012-05-05
相关资源
最近更新 更多