【问题标题】:Algorithm to match a sequence in a given n*m matrix匹配给定 n*m 矩阵中的序列的算法
【发布时间】:2018-02-17 11:48:51
【问题描述】:

我有一个 n*m 维度的矩阵,我打算将一组数字与给定的矩阵匹配。如果图案落在矩阵的垂直或水平列中,这非常简单,但如果图案以对角线方式落入,我无法检测到它。 例如,如果我必须匹配以下矩阵中的给定模式 [-1 , -1 , -1 ]

0 0 0 -1 0

0 0 -1 0 0

0 -1 0 0 0

1 0 -1 -1 -1

在上述情况下,我应该能够以对角线方式检测 -1 组以及最后一行中的组。

我也可以在哪里输入

-1 0 0 -1 0

0 -1 0 0 0

0 -1 -1 0 0

1 0 -1 -1 -1

在这种情况下,要检测从右到左的对角线以及最后一行序列。 基本上在给定的序列上,我必须能够检测到它的存在,它可以以垂直方式或水平或对角方式存在。

我的问题:算法必须检测“所有”序列,无论其水平、垂直或对角线是否存在。另外,请记住矩阵维度是 N*M,因此它可以是任意大小。

【问题讨论】:

  • 你的问题是......?
  • 你的算法必须找到所有吗?还是只有一个?示例:在您的最后一个矩阵中是否应该找到所有 3 个?
  • 每个位置是否总是相同的数字——你永远不需要匹配,例如,[1 2 3]?
  • glowcoder:在我的最后一个矩阵中,左上角只有 2 个相似的模式 -1 和最后一行的 -1 序列。

标签: algorithm


【解决方案1】:

我会注意到,您可以(有点详尽地)以不同的步长(1、m-1、m、m+1)迭代 n 行 m 列矩阵(被视为单个向量)。在每个步幅处从每个位置开始(直到步幅超出向量末端的点)并查看是否有匹配项。

这至少消除了水平、垂直和两条对角线的四种不同算法。

虽然在算法顺序方面相当丑陋——几乎是 N 平方。

(好吧,也许不是。你可以用一个循环来限定起始单元格,用于所有四种可能性。所以,一旦找到开始,检查四个步幅。所以你应该能够用一个来检查所有内容基本通过矩阵。)

【讨论】:

  • Daniel,你能用一个例子来详细说明你的解决方案吗?我无法理解不同的步幅将如何消除对 4 种不同算法的需求
  • 一种算法,4 步。 “矢量化”您上面的 4 x 5 示例,从头开始扫描第一个匹配的数字,然后依次使用 1、3、4 和 5 的步幅来检查剩余的数字。
【解决方案2】:

不管优化技术如何,这个问题的一个更通用的版本是这样的:

您有一个元素数组,其中每个元素都是一个数字及其相对于彼此的相对位置。

例如从左到右的数字 60,50,40,30 列表看起来像 (60,0,0) (50,1,0) (40,2,0) (30,3,0)。如果这是一个从上到下的列表,它将是 (60,0,0) (50,0,1) (40,0,2) (30,0,3)。如果它是从左上角到右下角的对角线,它将是 (60,0,0) (50,1,1) (40,2,2) (30,3,3)。

因此,通过这种方式,问题变得更加通用: 您想在矩阵中以通用坐标指定方向查找数字列表。

一般算法如下所示:

For each configuration
    For each coordinate of the matrix
        For each element in the list and corresponding local coordinate
            Add the local coordinate to the coordinate within the matrix
            If the value at that coordinate in the matrix does not match go to next configuration
    We found a match! Prosperity and happiness!

像往常一样,魔鬼在细节中。具体来说,在这种情况下,您实际上并不想遍历矩阵的所有坐标。您真正想要的是遍历所有坐标,当添加到模式中时会产生匹配的可能性,而不会超出矩阵。 (那样做的错误检查要少得多。)

这是一个简单的 2D 裁剪问题。在配置的相对定位值中找到最低的 X 和 Y 以及最高的 X 和 Y。如果您使用的是基于零索引的矩阵,则希望起始坐标为 -lowX-lowY,最大坐标为 matrixMaxX - 1 - highXmatrixMaxY - 1 - highY

额外的好处是您可以添加任何您想要的形状,而不仅仅是上/下/左/右/四个对角线。但这取决于你。

【讨论】:

    【解决方案3】:

    虽然这是一个老问题,但我希望我的回答可以帮助别人。

    在从事井字游戏项目时,我试图概括一个我认为也可以解决您的问题的解决方案。 此实现将寻找“线条图案”(这意味着它仅适用于水平/垂直/对角线上的一系列元素。

    function lookForCombinationsOnGrid(grid, ...args) {
    /* This function looks for a linear sequence of elements (x, o, undefined) 
    on the grid. 
    It returns an array of all beginning and ending coordinates (x, y) for 
    the corresponding pattern. 
    Inputs:
    - grid, a system of coordinates with an x-axis and an inverted y-axis.   
    - elements can be any sort of built-in objects. 
    */
    
    let sequence = [];
    sequence.push(args[0]);
    args.reduce(function (accumulator, currentValue, currentIndex, args) {
        return sequence.push(currentValue);
    });
    console.log("sequence =", sequence);
    
    let testedArr;
    // Look for this combination horizontally. 
    let result1 = [];
    for (i = 0; i < grid.length; i++) {
        for (j = 0; j <= grid[i].length - sequence.length; j++) {
            testedArr = [];
            for (k = 0; k < sequence.length; k++) {
                testedArr.push(grid[i][j + k]);
            }
            if (testedArr.join() === sequence.join()) {
                let start = [j, i];
                let end = [j + sequence.length - 1, i];
                result1.push([start, end]);
            }
        }
    }
    console.log("Found", result1.length, "results horizontally. ");
    
    // Look for this combination vertically. 
    let result2 = [];
    for (i = 0; i < grid[0].length; i++) {
        for (j = 0; j <= grid.length - sequence.length; j++) {
            testedArr = [];
            for (k = 0; k < sequence.length; k++) {
                testedArr.push(grid[j + k][i]);
            }
            if (testedArr.join() === sequence.join()) {
                let start = [i, j];
                let end = [i, j + sequence.length - 1];
                result2.push([start, end]);
            }
        }
    }
    console.log("Found", result2.length, "results vertically. ");
    
    // Look for this combination diagonally. 
    let result3 = [];
    for (i = 0; i <= grid.length - sequence.length; i++) {
        for (j = 0; j <= grid[i].length - sequence.length; j++) {
            testedArr = [];
            for (k = 0; k < sequence.length; k++) {
                testedArr.push(grid[i + k][j + k]);
            }
            if (testedArr.join() === sequence.join()) {
                let start = [j, i];
                let end = [j + sequence.length - 1, i + sequence.length - 1];
                result3.push([start, end]);
            }
        }
    }
    console.log("Found", result3.length, "results diagonally (left to right). ");
    
    // and diagonally the other way... 
    let result4 = [];
    for (i = 0; i <= grid.length - sequence.length; i++) { // line i = 0
        for (j = grid[i].length-1 ; j >= 0 + sequence.length-1; j--) { // column j = 1
            testedArr = [];
            for (k = 0; k < sequence.length; k++) {
                testedArr.push(grid[i + k][j - k]); // + 1 line to i, -1 col to j
            }
            if (testedArr.join() === sequence.join()) {
                let start = [j, i];
                let end = [j - sequence.length + 1, i + sequence.length - 1];
                result4.push([start, end]);
            }
        }
    }
    console.log("Found", result4.length, "results diagonally (right to left). ");
    
    let result = result1.concat(result2);
    result = result.concat(result3);
    result = result.concat(result4);
    
    return result;
    }
    grid = [[1, 1, 3],
            [1, 1, 1],
            [1, 1, 1],
            [0, 1, 1]];
    console.log(lookForCombinationsOnGrid(grid, 1, 1, 1, 0 ));
    

    我希望这可以帮助某人。

    【讨论】:

      猜你喜欢
      • 2021-12-31
      • 1970-01-01
      • 2014-02-09
      • 2012-05-18
      • 2018-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多