【问题标题】:Get permutations of all the array [1, 1, 1, 1, 1, 0, 0, 0, 0]获取所有数组 [1, 1, 1, 1, 1, 0, 0, 0, 0] 的排列
【发布时间】:2020-05-09 23:18:00
【问题描述】:

我正在尝试创建一个脚本来生成二进制开关的所有各种排列,其中应该有 5 个1 和 4 个0。并且数组的大小应该是9

我尝试了以下代码。排列的条件是: 1.数组集应该是唯一的。 2. 相邻的1不超过3个

const row = [1, 1, 1, 1, 1, 0, 0, 0, 0];
const list = [];
const fullList = [];

// To make sure that no more than 3 `1` are next to each other
const isRowValid = (row) => {
  let isValid = true;
  for(let i = 0; i+2 < row.length; i++) {
    if(row[i] === 1 && row[i+1] === 1 && row[i+2] === 1) {
      isValid = false;
      break;
    }
  }
  return isValid;
}


const combinations = (row, baseIndex, currentIndex, iterationLevel, list) => {
  if(currentIndex > row.length - iterationLevel) {
      baseIndex++;
      currentIndex = 0;
  }

  if(baseIndex + iterationLevel > row.length) {
    baseIndex = 0;
    iterationLevel++;
  }

  if(iterationLevel === 5) {
    return;
  }

  let rowCopy = [...row]
  if(baseIndex > currentIndex ) {
    let first = [...row.slice(0, currentIndex)];
    let second = [...row.slice(currentIndex)];
    let value = second.splice(baseIndex - currentIndex, iterationLevel);
    rowCopy =  [...first, ...value, ...second]
  } else if(baseIndex < currentIndex) {
    let first = [...row.slice(0, currentIndex + iterationLevel)];
    let second = [...row.slice(currentIndex + iterationLevel)];
    let value = first.splice(baseIndex, iterationLevel);
    rowCopy = [...first, ...value, ...second];
  }
  if(isRowValid(rowCopy)) {
      list.push(rowCopy);
  }
  console.log(rowCopy);
  combinations(row, baseIndex, currentIndex + 1, iterationLevel, list);
}

combinations(row, 0, 0, 1, list);
list.forEach(l => combinations(l, 0, 0, 1, fullList));

// To remove duplicates
for(let i = 0; i < fullList.length; i++) {
  const base = fullList[i]
  for(let j = i + 1; j < fullList.length; j++) {
    const isSame = fullList[j].every((l, m) => base[m] === l);
    if(isSame) {
      fullList[j] = [];
    }
  }
}

let filtered = fullList.filter(l => l.length !== 0);
console.log(filtered.length);

filtered.slice(0, 100).map(i => console.log(i));
console.log(fullList.length);

JS Bin

【问题讨论】:

  • 不清楚你在问什么。
  • 预期输出是什么?
  • 你的意思是排列而不是组合?

标签: javascript arrays typescript combinations


【解决方案1】:

如果我理解正确,您的意思是排列而不是组合,在每个排列中,“打开”的顺序开关不应超过 3 个。

当您必须生成排列或组合时,您可以使用递归回溯算法。

这个想法很简单,在每一步都遵循可能的选择,直到满足基本条件(例如,由于perm.length === switchCount,排列完成)。采取步骤时,您会将该选择反映在问题的状态上,而当递归调用返回时,您会撤消这些影响。

为了确定在每个步骤中可以做出哪些选择,我们需要跟踪问题的状态。在这里,我们只需要知道我们还剩下多少个 on/off 开关,以及到目前为止我们有多少个顺序 on 开关 (seqOn)。

const perms = permute(5, 4);

console.log(perms.length);
console.log(perms);

function permute(on, off) {
  const switchCount = on + off;
  const perm = [], perms = [];

  p(on, off, 0);

  return perms;

  function p(on, off, seqOn) {
      if (perm.length === switchCount) {
          perms.push([...perm]);
          return;
      }

      if (on && seqOn < 3) {
          perm.push(1);
          p(on - 1, off, seqOn + 1);
          perm.pop();
      }

      if (off) {
          perm.push(0);
          p(on, off - 1, 0);
          perm.pop();
      }
  }
}

如果我们有许多排列要枚举,我们也可以通过使用生成器来节省内存。在这里,我产生了相同的 perm 数组,它保存了 O(n) 时间副本。只要您不需要保留副本而只需枚举开关就可以了。

for (const perm of permute(5, 4)) {
    console.log(perm);
}

function* permute(on, off) {
    const switchCount = on + off;
    const perm = [];

    yield* p(on, off, 0);

    function* p(on, off, seqOn) {
        if (perm.length === switchCount) {
            yield perm;
            return;
        }

        if (on && seqOn < 3) {
            perm.push(1);
            yield* p(on - 1, off, seqOn + 1);
            perm.pop();
        }

        if (off) {
            perm.push(0);
            yield* p(on, off - 1, 0);
            perm.pop();
        }
    }
}

【讨论】:

  • 这是一个优雅的解决方案
  • @RokoC.Buljan 谢谢!添加了一个使用生成器的变体,这可能很有趣;)
  • @plalx 感谢您的纠正,我的意思是排列而不是组合。并且解决方案很好解释,生成器功能很棒。
  • @Sumit 只是好奇。这是针对现实世界的问题吗?
  • @plalx 是的。我正在设计一款需要所有此类排列列表的游戏。
猜你喜欢
  • 2017-11-28
  • 2018-09-26
  • 2019-12-03
  • 2012-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-23
相关资源
最近更新 更多