用于匹配给定n * m矩阵中的序列的算法

时间:2011-09-30 22:27:03

标签: algorithm

我有一个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组。

我还可以在

中输入一个输入
  

-1 0 0 -1 0

     

0 -1 0 0 0

     

0 -1 -1 0 0

     

1 0 -1 -1 -1

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

我的问题:算法必须检测“所有”序列,无论其是水平,垂直还是对角存在。另外,请记住矩阵尺寸为N * M,因此它可以是任何尺寸。

3 个答案:

答案 0 :(得分:1)

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

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

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

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

答案 1 :(得分:0)

无论优化技术如何,此问题的更通用版本都是这样的:

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

E.g。从左到右的数字列表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

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

答案 2 :(得分:0)

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

在开展tic-tac-toe项目时,我尝试推广一个我认为可以解决您问题的解决方案。 此实现将查找“线条图案”(这意味着它仅适用于水平/垂直/对角线上的一系列元素。

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

我希望这可以帮助别人。