在次线性时间搜索2D数组

时间:2016-04-23 19:50:58

标签: java arrays algorithm

这是最近的编码访谈中的一个问题

编写一个有效的算法,搜索m×n矩阵中的值。

此矩阵具有以下属性:

  1. 每行中的整数按从左到右的升序排序。

  2. 每列中的整数按从上到下的顺序排序

      [1,   4,  7, 11, 15]
    
      [2,   5,  8, 12, 19]
    
      [3,   6,  9, 16, 22]
    
      [10, 13, 14, 17, 24]
    
      [18, 21, 23, 26, 30]
    
  3. 有没有办法在O(mn)以下执行此操作。我无法看到如何在这个数组上进行二进制搜索,因为没有办法消除任何东西。

2 个答案:

答案 0 :(得分:2)

您可以使用这个简单的算法,利用这样一个事实:在具有这些属性的矩阵中,值mtx[i][j] 总是小于任何值mtx[x][y],其中{{ 1}}或x > i,换句话说,右边和右边的任何值:

y > j

我们的想法是逐行搜索,如果找到一个更大的值,您可以停止查看此行,并且您知道在以后的行中不必搜索该列。如果行的第一个值大于该值,则可以停止搜索并返回false。此外,在每行搜索结束时,检查public static boolean find(int[][] mtx, int val) { int maxCol = mtx[0].length, minCol = 0; for(int i = 0 ; i < mtx.length ; i++) { for(int j = minCol ; j < maxCol ; j++) { if(val == mtx[i][j]) return true; if(val < mtx[i][j]) { maxCol = j; break; } } if(maxCol == 0) break; minCol = 0; if(i != mtx.length-1 && val > mtx[i+1][maxCol-1]) minCol = maxCol-1; } return false; } 下一行的单元格,如果值较大,则在下一个循环中,您可以跳过前面的每个单元格。

最糟糕的情况是最大值(或更大),复杂度为O(m + n),因为它会检查所有第一行,然后跳过下一行m。

答案 1 :(得分:0)

对于给定值x,有一个边界在矩阵中游荡,或多或少从左下角到右上角,总是向右或向上行进,并且将大于x的值与小于或等于x的值分开

从左上角开始,沿直线对角线向下和向右搜索,直到找到这个锯齿状边界。 (如果首先到达矩阵的边界,只需沿着该边界向右或向下,继续搜索。)然后沿两个方向沿边界步进,直到找到x或者没有更多的矩阵单元要搜索。

此搜索可以遍历三个路径部分,每个路径部分仅向右 - 向下,向右 - 向上或向左 - 向下。这些路径的长度为O(m + n)。因此整个搜索是O(m + n)。