在二维阵列中找到菱形的最快方法是什么?

时间:2012-10-10 12:42:12

标签: algorithm

以下是我的问题的可视化:

enter image description here

我需要找到存放在正方形中的最有价值的菱形。 我正在考虑这几天但直到现在,除了使用'for loop'并检查每个可能的菱形之外,我没有找到任何其他东西。你们怎么看待这个?这是我能做到的唯一方法吗? :P谢谢:)

3 个答案:

答案 0 :(得分:1)

以下是我的想法:

第一次迭代,您遍历矩阵,但是对角线。你从最左上角开始,你可以适合你的菱形(或菱形的一面),你看看菱形大小所覆盖的元素。

  • 首先检查elems(0,1)和(1,0)(a)
  • 接下来你检查(0,2)和(1,1)(b)
  • (1,1),(2,0)(b)
  • (0,3),(1,2)(c)
  • (1,2),(2,1)(c)
  • ...

我希望你能得到检查令。你对这些元素的处理是你总结: e(0,1)+ e(1,0)= 11 e(0,2)+ e(1,1 )= 3 等等。你必须注意到,当你处理同一行上的元素(上面标有相同字母的元素)时,你不必再次计算总和:那里有一个元素外出,一个进入,所以你只访问两个元素来获得新的总和。

第二次迭代,您沿着对角线遍历矩阵,但是从另一侧。您从右上角开始,并处理先前计算的总和。因此,您要检查的第一对将位于(0,3),(1,4)。你做的事与以前完全相同:你再次计算金额。

现在,在第二次迭代结束时,每个处理过的字段实际上都包含稀疏菱形的总和,该字符在该字段中有一个上角。 3x3菱形的示例如下图所示:

Sparse 3x3 rhomb

第3步从图像中可以看出, n 稀疏菱形是"缺少"另一个稀疏菱形 - 大小为(n-1)的菱形。迭代1和2正是为图像中所有大小为 n 的稀疏rhombs找到和的过程。因此,作为第3步,我们再次进行第1次和第2次迭代,但不是我们正在搜索的大小( n ),而是使用大小(n-1) )注意表示"搜索"对于大小1等于输入矩阵(例如,如果n = 2,对于第3步,你不必计算任何东西)。

最后,对于顶部位置(0,2)的3x3菱形感兴趣的总和是来自前两次迭代的(0,2)处的和,以及来自(1,2)的总和第三步。您可以将这两个加在一起:对于位置(x,y)的前两个过程的结果矩阵中的每个元素,可以在第3步结果矩阵的位置(x,y + 1)添加元素。 现在你只需找到最大值,你就可以得到关于菱形的最大值和位置的答案。

你在4次传球中完成所有这些操作(你可以在计算第2次传球时跟踪最大值) - 所以这会给出O(4*n^2) = O(n^2)的复杂性,其中n的大小是广场的大小。

希望它清楚,如果我弄清楚了我的答案,请要求澄清。


2x2菱形的示例

第一次通过

 -1 11  3  7  5     * / * * * 
 -1  9 14 12  3     / * * * *
 -1 12 18  4  6     * * * * * 
 -1 11  3  6  2    * * * * * 
 -1 -1 -1 -1 -1     * * * * *

第二遍

 -1 25 15 10 -1    * * * \ *
 -1 27 18 18 -1    * * * * \
 -1 15 24  6 -1    * * * * *
 -1 -1 -1 -1 -1    * * * * *
 -1 -1 -1 -1 -1    * * * * *

第3步

由于 n = 1 ,第3遍不需要计算任何东西,第三遍的输出是输入矩阵

 1  2  2  2  2
 9  1  5  3  1
 8  9  9  2  3
 3  9  2  3  1
 2  1  3  1  1

现在,我们只需要将第二次迭代的输出与第三步的输出相加(向上移动一位)。我们得到:

 -1 26 20 13 -1    
 -1 36 27 20 -1    
 -1 24 26  9 -1    
 -1 -1 -1 -1 -1    
 -1 -1 -1 -1 -1    

<强>答案 在(1,1)处有一个上角的菱形是最有价值的一个,总和为31。

注意: -1是一个菱形边不适合的地方 - undefined sum。您可以在程序中以您想要的方式标记它(特别是如果您的矩阵中实际上可以有负值)。在第二遍中,您可以将具有 undifined 元素的任何总和设置为 undifined

注意2:无论菱形大小是什么,当你通过矩阵滑动菱形边时,一个数字总是进来而另一个数字来自总和(除非你和#39;重新进入新行。)

注3:第2次和第2次通过中菱形的第一个位置在数组中标有/\


示例3x3菱形

让我在同一个矩阵上做3x3菱形,以表明复杂度为O(n^2)(其中n是方形大小的大小),一般情况下不是仅适用于2x2菱形。

让我们调用输入矩阵z[][],即第一遍f[][]后的矩阵,以及第二遍后的矩阵s[][]

第一次通过

  1. f[0][2] = z[0][2] + z[1][1] + z[2][0] == 11 (a)
  2. f[0][3] = z[0][3] + z[1][2] + z[2][1] == 16 (b)
  3. f[1][2] = f[0][3] - z[0][3] + z[3][0] == 17 (b)
  4. f[0][4] = z[0][4] + z[1][3] + z[2][2] == 14 (c)
  5. f[1][3] = f[0][4] - z[0][4] + z[3][1] == 21 (c)
  6. f[2][2] = f[1][3] - z[1][3] + z[4][0] == 20 (c)
  7. f[1][4] = z[1][4] + z[2][3] + z[3][2] == 5 (d)
  8. f[2][3] = f[1][4] - z[1][4] + z[4][1] == 5 (d)
  9. f[2][4] = z[2][4] + z[3][3] + z[4][2] == 9 (e)
  10. 您最多访问一次元素。标有不同字母的是同一行的总和。在该行的第一个总和中,您必须将与菱形边相同的元素相加,我们将其称为m菱形m x m。在该行的每个其他总和中,总是必须正好访问3个元素:前一个总和,即出去的元素(带有-符号的元素),和那个进入的人(+)。

     -1 -1 11 16 14 
     -1 -1 17 21  5 
     -1 -1 20  5  9 
     -1 -1 -1 -1 -1 
     -1 -1 -1 -1 -1 
    

    第二遍

    然后你在第二遍中做了类似的事情(我不打算把它们写出来),你只需要少一些元素。

     -1 -1 41 -1 -1 
     -1 -1 -1 -1 -1 
     -1 -1 -1 -1 -1 
     -1 -1 -1 -1 -1 
     -1 -1 -1 -1 -1 
    

    第3步

    此步骤与 2x2示例 1st 2nd iteration 完全相同。因此,2x2稀疏rhombs的总和是:

     -1 25 15 10 -1    
     -1 27 18 18 -1    
     -1 15 24  6 -1    
     -1 -1 -1 -1 -1    
     -1 -1 -1 -1 -1    
    

    当我们总结第二次迭代的输出时,我们得到:

     -1 -1 59 -1 -1 
     -1 -1 -1 -1 -1 
     -1 -1 -1 -1 -1 
     -1 -1 -1 -1 -1 
     -1 -1 -1 -1 -1 
    

    回答只有一个3x3菱形适合矩阵,因此矩阵中只剩下一个元素,这恰好是唯一适合的菱形的总和:59。

答案 1 :(得分:1)

如果问题是关于在菱形'内核'中找到最大的总和,那么是的,有更快的算法。

佩内洛普提出的算法是一个很好的起点 - 然而,当菱形尺寸变大时,所需的进出部分数量增加。这可以通过二维第一次通过来避免,它在两个方向上对角积分值。

[ a b c d]  --> integrate a, a+f, a+f+k, a+f+k+p right down    
[ e f g h]      then integrate the elements in positions c,f,i etc. 
[ i j k l]
[ m n o p] 

与找到对齐方块的总和相比,这种方法的缺点是必须计算一组单独的对角线,(x + y)是奇数,而(x + y)是偶数;然后结果来自抽样8个积分和而不是4个。

我相信通过从左到右和从上到下整合来最容易理解方法(求和区域)

[1 2 0 3]       [1 3 3 6]        here every cell contains the summed area
[0 0 1 1]       [1 3 4 8]        of M[I][J] := sigma i=0..I,j=0..J m[i][j]
[1 0 3 1]  -->  [2 4 8 13]
[0 1 1 1]       [2 5 10 16] 

要获得该区域(8..16,100..983),必须只能访问角落元素:

Sigma i=8..16,j=100..983 m[i][j] :== M[7][99]+M[16][983]-M[7][983]-M[16][99]

当要整合的形状旋转45度时,我们必须计算两组积分。如果这是一个棋盘,分别用于白色和黑色方块。然后,每个菱形将由来自一个矩阵M_odd的N * N大小的求和区域和来自另一个求和区域矩阵M_even的(N-1)*(N-1)大小的求和区域组成(反之亦然)。这可以扩展到任何菱形尺寸,具有相同的复杂性。 (并且当N = 1或N = 2时,可以优化从矩阵m中加入元素,并且对于正方形N> 2使用矩阵M)。

评论:也许这等于佩内洛普的建议,但是,我无法弄明白,因为缺乏从5元素菱形到任意大小的概括。

答案 2 :(得分:-1)

我认为使用flood_fill算法只需一次通过,你可以在其中“绘制”相似的颜色区域,即不可见 - 即清除它们。您总结内容并记录两个轴中每个访问像素位置的直方图。 (您可以保持最小和最大x / y位置的计数)。如果直方图遵循轴[1,3,1],[1,3,5,3,1]中的特定模式,则绘制的区域是菱形,否则再次检查这些像素是没有用的,是吗?

   131                        13432
 1  #                      1    #
 3 ###                     4   ####
 1  #  <-- is a rhomb      4  ## ##
                           3   ###
                           1    # <- isn't