用于检查矩阵中的行/列中的5的更好算法

时间:2011-11-11 08:08:54

标签: python algorithm matrix

是否有一个很好的算法来检查一行或一列中是否有5个相同的元素,或者对角线给出方形矩阵,比如6x6?

有一种天真算法可以迭代每个点然后对于矩阵中的每个点,遍历该行,然后是对角线。我想知道是否有更好的方法。

7 个答案:

答案 0 :(得分:3)

您可以在字典中保留直方图(映射元素类型 - > int)。然后你迭代你的行或列或对角线,然后递增histogram[element],并在最后检查以查看直方图中是否有任何5,或者如果你可以允许超过5个副本,你可以只是任何元素达到5后停止。

简单,一维,例如:

m = ['A', 'A', 'A', 'A', 'B', 'A']

h = {}
for x in m:
    if x in h:
        h[x] += 1
    else:
        h[x] = 1

print "Histogram:", h

for k in h:
    if h[k]>=5:
        print "%s appears %d times." % (k,h[k])

输出:

Histogram: {'A': 5, 'B': 1}
A appears 5 times.

基本上,h[x]将存储元素x在数组中出现的次数(在您的情况下,这将是当前行,或列或对角线)。元素不必连续出现,但每次开始考虑新的行/列/对角线时,计数都会重置。

答案 1 :(得分:1)

您可以在单次传递中检查整数矩阵中是否有相同的元素。

假设n是矩阵的大小,m是最大的元素。我们有n列,n行和1对角线。 Foreach列,行或对角线我们最多有n个不同的元素。

现在我们可以创建一个包含(n + n + 1)*(2 * m + 1)元素的直方图。代表 行,列和对角线,每个都包含至多n个不同的元素。

size = (n + n + 1) * (2 * m + 1)
histogram = zeros(size, Int)

现在棘手的部分是如何更新这个直方图?

在伪代码中考虑这个函数:

updateHistogram(i, j, element)

    if (element < 0)
        element = m - element;

    rowIndex        = i * m + element
    columnIndex     = n * m + j * m + element
    diagonalIndex   = 2 * n * m + element

    histogram[rowIndex] = histogram[rowIndex] + 1
    histogram[columnIndex] = histogram[columnIndex] + 1

    if (i = j)
        histogram[diagonalIndex] = histogram[diagonalIndex] + 1

现在你所要做的就是迭代抛出直方图并检查是否有一个元素&gt; ķ

答案 2 :(得分:0)

对于行,您可以保留一个计数器,该计数器指示您当前拥有的行中有多少相同的元素。为此,请遍历行和

  • 如果当前元素与前一个元素匹配,则将计数器增加1。如果counter是5,那么你找到了你想要的5个元素。
  • 如果当前元素与前一个元素不匹配,请将计数器设置为1。

同样的原理也可以应用于列和对角线。您可能希望对列(每列一个元素)和对角线使用计数器数组,以便您可以迭代矩阵一次。

我为一个较小的案例做了一个小例子,但你可以很容易地改变它:

n = 3
matrix = [[1, 2, 3, 4], 
          [1, 2, 3, 1], 
          [2, 3, 1, 3],
          [2, 1, 4, 2]]
col_counter = [1, 1, 1, 1]
for row in range(0, len(matrix)):
    row_counter = 1
    for col in range(0, len(matrix[row])):
        current_element = matrix[row][col]

        # check elements in a same row
        if col > 0:
            previous_element = matrix[row][col - 1]
            if current_element == previous_element:
                row_counter = row_counter + 1
                if row_counter == n:
                    print n, 'in a row at:', row, col - n + 1
            else:
                row_counter = 1

        # check elements in a same column
        if row > 0:
            previous_element = matrix[row - 1][col]
            if current_element == previous_element:
                col_counter[col] = col_counter[col] + 1;
                if col_counter[col] == n:
                    print n, 'in a column at:', row - n + 1, col
            else:
                col_counter[col] = 1

我省略对角线以保持示例简洁明了,但对于对角线,您可以使用与在列上使用相同的原则。前一个元素将是以下之一(取决于对角线的方向):

matrix[row - 1][col - 1]
matrix[row - 1][col + 1]

请注意,在第二种情况下,您需要付出额外的努力。例如,从右到左遍历内循环中的行。

答案 3 :(得分:0)

您最好的方法可能取决于您是否控制元素的位置。

例如,如果您正在构建游戏并将最新元素放置在网格上,则可以捕获与该点相交的垂直,水平和对角线条的四个字符串,并在每个条带上使用相同的算法计算每个元素并评估总数。算法可能略有不同,具体取决于您是否计算六个中的五个连续元素,或者只要总数为五个就允许间隙。

答案 4 :(得分:0)

我认为你不能避免迭代,但你至少可以对所有元素进行异或,如果结果是0 =&gt;他们都是平等的,那么你不需要做任何比较。

答案 5 :(得分:0)

您可以尝试使用一些启发式方法来改进您的方法:使用矩阵大小的知识来排除不适合的元素序列并暂停不必要的计算。如果给定的矢量大小为6,你想要找到5个相等的元素,前3个元素是不同的,进一步的计算没有任何意义。

如果连续5个相等的元素很少发生,这种方法可以给你一个显着的优势。

答案 6 :(得分:0)

如果将行/列/对角线编码为位图,“连续五行”表示“掩码%31 == 0&amp;&amp; mask / 31 == power_of_two”

  • 00011111:= 0x1f 31(连续五次)
  • 00111110:= 0x3e 62(连续五次)
  • 00111111:= 0x3f 63(连续六次)

如果你想把六合一的情况视为五行,最简单的方法可能是:

for ( ; !(mask & 1) ; mask >>= 1 ) {;}
return (mask & 0x1f == 0x1f) ? 1 : 0;

也许Stanford比特调整部门有一个更好的解决方案或建议需要循环?