这是最近的编码访谈中的一个问题
编写一个有效的算法,搜索m×n矩阵中的值。
此矩阵具有以下属性:
每行中的整数按从左到右的升序排序。
每列中的整数按从上到下的顺序排序
[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]
有没有办法在O(mn)以下执行此操作。我无法看到如何在这个数组上进行二进制搜索,因为没有办法消除任何东西。
答案 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)。