如何在有序矩阵中高效搜索? [复制]

Posted

技术标签:

【中文标题】如何在有序矩阵中高效搜索? [复制]【英文标题】:How to efficiently search in an ordered matrix? [duplicate] 【发布时间】:2011-04-13 00:11:48 【问题描述】:

我有一个x by y 矩阵,其中每一行和每一列都按升序排列,如下所示。

1   5   7    9
4   6   10   15
8   11  12   19
14  16  18   21

如何在此矩阵中搜索O(x+y) 中的数字?

我在面试时被问到这个问题,但不知道该怎么做。很想知道是否可以做到。

【问题讨论】:

听起来与geeksforgeeks.org/forum/topic/…类似 【参考方案1】:

从第一行的最后一个元素开始(右上角)。 将其与key 进行比较。我们有 3 个案例:

如果它们相等,我们就完成了。

如果key 大于该元素 那么这意味着key 不能存在 在该行中,所以移动搜索 到它下面的元素。

如果key 小于那个元素,那么 这意味着key 可能出现在那个 行向左,不能出现在更下方的列中,因此移动搜索 到它左边的元素。

一直这样做,直到找到元素或无法进一步移动(键不存在)。

伪代码:

Let R be number of rows
Let C be number of columns

Let i = 0
Let j = C-1

found = false
while( i>=0 && i<R) && (j>=0 && j<C) )
   if (matrix[i][j] == key )
      found = true
      break
   else if( matrix[i][j] > key )
       j--
   else if( matrix[i][j] < key )
       i++
end-while

【讨论】:

我看不到这个工作。假设我在上面的数组中搜索key=11,这个算法是怎么找到的? @Ashley:我们从9 开始。 11 > 9 所以向下移动。 11 15 向左移动。 11 > 10 向下移动。 11 12 向左移动。 11 == 11 @codaddict:downvotes 不再解释:/ 这是在排序矩阵中搜索的经典算法,基本思想是您在一个对角线方向对矩阵进行排序并沿另一个对角线方向迭代。因此,您也可以从左下角开始 :)【参考方案2】:

将矩阵拆分为 4 个子矩阵。如果子矩阵的右下角小于 key,则丢弃它。如果子矩阵的左上角大于键,则丢弃它。对剩余的子矩阵重复拆分过程。

[更新] 有关一些伪代码(以及对复杂性的讨论),请参阅 Jeffrey L Whitledge 对this question 的回答。

【讨论】:

那应该有更好的性能:O(log x + log y) ?! 它可能更快,但需要更多内存。 如何将矩阵拆分为 4 个子矩阵?到什么时候再重复?您什么时候知道该元素不存在?开始编写伪代码,你会发现这并不容易。 @Landei - 内存不会和 x*y 一样吗? 实际上,这将是 O(2 ^ log x + 2 ^ log y),因为在每个步骤中,您需要递归超过 2(或三个,但您可以改进以避免这种情况)子-矩阵。这是 O(x + y)【参考方案3】:
// the matrix is like this, from left to right is ascending, and
// from down to up is ascending, but the second row'start is not always bigger than the first row's end, which is diff from [leetcode]https://oj.leetcode.com/problems/search-a-2d-matrix/
// 1   5   7    9
// 4   6   10   15
// 8   11  12   19
// 14  16  18   21
// time complexity is O(x+y), x is the count of row, and y is the count of column

public boolean searchMatrix2(int[][] matrix, int target) 
    int rowCount = matrix.length;
    if(rowCount == 0) return false;

    int colCount = matrix[0].length;
    if(colCount == 0) return false;

    //first find the target row, needs O(x)
    int targetRow = 0;
    while(targetRow < rowCount-1 && matrix[targetRow+1][0] <= target) 
        targetRow++;
    
    //than find the target in the target row, needs O(y), so the total is O(x)+O(y)
    boolean result = false;
    for(int i = 0; i < colCount; i ++) 
        if(matrix[targetRow][i] == target) 
            result = true;
            break;
        
    
    return result;

其实我们可以使用两次二分查找,先二分查找目标行,再二分查找行中的目标,所以时间复杂度为O(lgx) + O(lgy),为O( lgx + lgy),比 O(x+y) 更好。

【讨论】:

以上是关于如何在有序矩阵中高效搜索? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode74. 搜索二维矩阵

240. 搜索二维矩阵 II

java 在有序矩阵中搜索

算法--有序矩阵查找指定数

排序练习题:有序矩阵查找

如何高效的对有序数组去重