【问题标题】:How do I find all permutations from a series of arrays that act as rows and columns in javascript?如何从一系列在 javascript 中充当行和列的数组中找到所有排列?
【发布时间】:2021-03-29 12:47:12
【问题描述】:

这是我的示例数据结构:

r 代表行。

var data = {
  r0: ["E9", "55", "1C"],
  r1: ["1C", "E9", "E9"],
  r2: ["BD", "1C", "55"]
}

我将如何找到路径不能相同的所有路径,路径只能水平遍历(并且只能从第 0 行开始),然后是垂直,然后是水平等,在它无法选择的路径中相同的值。但是,如果在当前行/列中检测到有效值,则路径可以“跳转”值。

索引0开始。

未来算法输出的预期路径示例:

RowColumn(value),....

// these paths stop because there are no more valid vertical or horizontal values to pick.
00(E9), 10(1C), 11(E9), 01(55), 02(1C), 22(55), 12(E9)
02(1C), 22(55), 20(BD), 00(E9), 01(55), 21(1C), 11(E9), 10(1C), 12(E9)

【问题讨论】:

  • 如果你必须手工完成,你会怎么做?一旦你弄清楚了,你就需要学习把它转换成代码。
  • 能否详细说明最终结果?看来您需要的是展平您的 data 数组
  • 我已经为它做了算法,结果发现没有解决方案:'(如果你必须水平,然后垂直,然后水平等等,没有办法使这项工作在 3x3 网格中。您的预期结果不符合该规则(您连续水平两次:02, 12, 22
  • 看起来我完全掩盖了垂直水平垂直等。部分......我们需要在这里做更多的澄清; @blex 是正确的,因为当您必须 每次移动都交替垂直/水平时,覆盖 3x3 网格中的所有元素是不可能的。感觉可能缺少一些信息。
  • 我犯了一个错误,不小心写了 2 个垂直移动(正如 blex 指出的那样)。目标不是覆盖整个 3x3(或更大)的网格,而是从第一行开始找到所有可能的路径。路径可以是任意数量的长度。必须从第一行水平开始(选择任何值),然后选择垂直值(同时不选择任何已经选择的值)。路径可以“跳过”自身,但不能选择相同的值。

标签: javascript arrays path permutation


【解决方案1】:

本答案中使用的规则

在阅读您的问题时,我了解到规则是:

  • 0_0开始
  • 从水平开始
  • 每次移动时交替水平/垂直
  • 永远不要两次访问同一个单元格
  • 我们可以跳过已经访问过的单元格
  • 路径不必覆盖整个网格

算法

要让每条路径都遵循这些规则,您可以使用递归函数(一个调用自身的函数)

在以下示例中,它采用 2 个参数:

  • 路径:访问过的单元格数组
  • horizo​​ntal:一个布尔值,描述我们是否应该水平移动

第一次调用它时,我们给它一个包含第一个单元格 (['0_0']) 和 true 的路径,因为我们必须水平移动。

然后:

  • 查找与上次访问的单元格在同一行或同一列中尚未添加到路径中的单元格(水平或垂直取决于当前方向)
  • 为每个 nextCells 调用自身,将该单元格添加到路径和切换方向

代码

function rowColumn(obj) {
  // Convert the Object to a 2D Array
  const data = Object.values(obj),
        rows = data.length,
        cols = data[0].length,
        res  = [];
  
  function recursive(path, horizontal) {    
    // Get the row or column cells that haven't been visited yet
    const nextCells = getNextCells(path, horizontal);
    
    // If no neighbors were found, push the result and return
    if (!nextCells.length) return res.push(path);
    
    // Apply recursion for all possible neighbors
    nextCells.forEach(cell => recursive(path.concat(cell), !horizontal));
  }
  
  function getNextCells(path, horizontal) {
    const [x, y] = path[path.length - 1].split('_').map(v => +v);
    let cells = [];
    
    if (horizontal) cells = Array.from({length: cols}, (_, i) => `${i}_${y}`);
    else            cells = Array.from({length: rows}, (_, i) => `${x}_${i}`);

    // Remove the cells that have already been visited
    return cells.filter(p => !path.includes(p));
  }
  
  // Start the recursion
  recursive(['0_0'], true);
  // Format the result
  return res.sort((a, b) => a.length - b.length)
            .map(path => path.map(cell => {
              const [x, y] = cell.split('_').map(v => +v);
              return `${x}${y}(${data[y][x]})`;
            }));
}

const data = {
  r0: ["E9", "55", "1C"],
  r1: ["1C", "E9", "E9"],
  r2: ["BD", "1C", "55"],
};

const res = rowColumn(data);
console.log(
  `There are ${res.length} paths possible:`,
  res.map(path => path.join(' '))
);

【讨论】:

  • 该算法工作得非常好 blex!我个人添加的只是创建一个循环来传递第一行中的所有单元格,以真正获得所有排列(不仅仅是从 0_0 开始)。你能告诉我你是怎么想出解决方案的吗?有一段时间,我一直把头撞在墙上,弄乱了 for 循环并短暂地干预了递归函数,但无济于事。是否有一些练习、问题或可能是您参加的课程使您能够创建这样的算法?谢谢
  • 太棒了!哦,那部分我没看懂,我以为所有路径都必须从0_0开始
  • 我不明白为什么你在'getNextCells'函数中创建另一个名为res的const变量,而主函数顶部已经创建了一个。我删除它进行测试,并有一个无限循环。你能向我解释一下你为什么要设置这个变量,以及它在做什么方面有什么意义吗?
  • 第一个与第二个无关,它们属于不同的范围。 rowColumn 中的一个存储发现的路径。 getNextCells 中的一个存储我们在特定方向上为特定单元格找到的邻居。但是现在我回顾代码,这个getNextCells 函数可以改进。我对其进行了编辑并将变量命名为cells,如果这样可以减少混淆
【解决方案2】:

// Trying to replicate output 00(E9), 10(1C), 11(E9), 01(55), 02(1C), 12(E9), 22(55), 21(1C), 20(BD)

const algo = (values) => {
  // Find the number of keys of the values/data object
  const totalKeys = Object.keys(values).length

  // Cycle through the keys with an assumption that the first key is always 'r0'
  for (let row = 0; row < totalKeys; row++) {
    // construct a key name
    const keyName = "r" + row

    // get the array associated with this key
    const arr = values[keyName]

    // loop through the array
    for (let column = 0; column < arr.length; column++) {
      // get the current value
      const value = arr[column]

      // do whatever you want to do with values, I am just printing them here
      console.log("" + row + column + "(" + value + ")")
    }
  }
}

const data = { // usage of var is discouraged, use let or const instead
  r0: ["E9", "55", "1C"],
  r1: ["1C", "E9", "E9"],
  r2: ["BD", "1C", "55"]
}

algo(data);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    相关资源
    最近更新 更多