【问题标题】:Find number in sorted matrix (Rows n Columns) in O(log n) [duplicate]在O(log n)中查找排序矩阵(行n列)中的数字[重复]
【发布时间】:2012-05-22 07:54:40
【问题描述】:

假设我有一个矩阵 (MxN),它的行和列已排序。

  1. 每行中的所有元素都按升序排列
  2. 每列中的所有元素都按升序排列
  3. 所有元素都是整数
  4. 无法做出其他假设

    示例:

    [1 5 8 20]

    [2 9 19 21]

    [12 15 25 30]

我必须找出给定的数字是否存在于矩阵中(基本搜索)。我有一个运行 O(n)

的算法
int row = 0;
int col = N-1;

while (row < M && col >= 0) {
  if (mat[row][col] == elem) { 
    return true;
  } else if (mat[row][col] > elem) { 
    col--;
  } else { 
    row++;
  } 
}

但有人问我O(log (MxN)) == O(Log(n)) 解决方案。有什么想法吗??

【问题讨论】:

  • 除了排序之外,你对矩阵的输入有什么了解(比如它的行/列大小,perhpas?)
  • @Yoel:嗯,它可以很大,只有整数,可以有负数。有什么具体要找的吗?
  • 每行的第一个元素是否保证大于上一行的最后一个元素? (如您的示例所示)在这种情况下,修改后的二进制搜索问题很简单
  • @BrokenGlass:不,这根本不能保证。唯一的条件是行按升序排序,列也是如此。
  • @phix23:我不确定。其实没想到。但是如果n = MxN 将其视为一个数组,您将如何进行搜索?

标签: performance algorithm


【解决方案1】:

由于行和列都已排序,如果我们查看每一行的第一个元素,我们可以找到哪个元素包含我们要查找的数字。然后,再次,我们可以利用每一行中的元素已排序并找到该数字的事实。
我知道最快的搜索算法是二分搜索,它的复杂度为 O(log n),所以总复杂度为 O(log m + log n)。
这是一个示例,假设我们要查找 28:

 1  2  3  4  5  6  7  8  9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
  • 我们对第一列(1、11、21、31、41)的元素进行二分查找,发现行是第三行,因为它的第一个元素小于我们的数字但是 em> 下一行的第一个元素更大。 步数:2(21、31、找到)
  • 我们再次对第三行(21、22、23、24、25、26、27、28、29、30)进行二分搜索并找到我们的号码。 步数:2 - 3(25、27 或 28,找到)

【讨论】:

  • 嗯.. 我认为那是O(MLog N) 不是吗?对于每一行(M) + 搜索(log N)
  • @noMAD:不,也许我解释错了。您只进行 2 次搜索
  • 那我不认为我理解你。你能改写一下吗?
  • @noMAD:现在检查。对不起我的英语;)
  • 此解决方案不起作用,因为根据 OP,不能保证行的开头数字大于前一行中最后一列的值 - 给出的示例矩阵只是不幸的
【解决方案2】:

你必须使用递归来解决这个问题。 给定一个矩阵 X 和数字 y,你可以在 X 的中间行对 y 进行二分搜索,并将矩阵分成四部分,这样:

A|B
---
C|D

A中的所有元素都小于y,D中的所有元素都大于y,并且y可以在B和C中。迭代地在B和C中找到y。

由于 height(A)=height(B)\approx= height(C)=height(D), size(X)>= 2*(size(B)+size(C)) 。因此,如果 O(logn) 产生复杂度。

def find(X,y):
    a,b = X.shape
    i = a /2
    j = binsearch(X[i,:], y)
    if X[i,j]==y:
        return True
    else:
        return find( X[ (i+1):a, 0:(j-1)], y ) or find( X[ 0:i, j:b], y )

【讨论】:

  • 这里还提供了一个完整的解决方案:leetcode.com/2010/10/searching-2d-sorted-matrix-part-ii.html
  • "由于高度(A)=高度(B)\近似=高度(C)=高度(D),尺寸(X)>= 2*(尺寸(B)+尺寸(C) ) 。因此,如果 O(logn),则产生的复杂性。 -> 没有
  • 你有 T(n)=2*T(n/2)+O(1),很抱歉,O(Log(n)) 不是这个方程的解。跨度>
  • @ElKamina:这种方法很好,但正如 Thomash 指出的那样,您的运行时间计算存在缺陷。
  • @ElKamina 反正 O(Log(n)) 不是 T(n)=2*T(n/4)+O(1) 的解。
【解决方案3】:

不可能比 O(n) 做得更好。有些人(这个页面上至少有三个人)认为他们可以做得更好,但那是因为他们的算法是错误的,或者因为他们不知道如何计算他们算法的复杂性,所以他们试图猜测它。 This blog post 很好,会解释这些人的错误。

O(n) 最优的证明草稿:考虑以下矩阵:

1     2     3     4     5     6 … (n-2)  (n-1) (n+1)
2     3     4     5     6     7 … (n-1)  (n+1) (n+2)
3     4     5     6     7     8 … (n+1)  (n+2) (n+3)
…     …     …     …     …     … … …      …     …
(n-2) (n-1) …     …     …     … … …      …     (2n-1)
(n-1) (n+1) …     …     …     … … …      …     2n
(n+1) (n+2) …     …     …     … … (2n-1) 2n    (2n+1)

如果您要在此矩阵中查找 n,则如果 n 在该行中,则必须对每一行至少检查一次,因为 n 可以在任何行中。 (证明不完整,但思路如下)

【讨论】:

  • +1 如果证据完全说服我,我会接受这个答案。但感谢那个可爱的链接。 :-)
  • @Thomash:虽然快一年了。但我只是对作者在上述博客文章中为“四分区”方法计算的算法复杂度感到好奇。因为我们将矩阵划分为“4”子矩阵并丢弃这四个中的一个。所以不应该是 T(n) = 3*T(n/4)+c 而不是 T(n) = 3*T(n/2)+c(这个由作者计算)
  • @Manish n in T(n) 是矩阵中的行数(或列数),而不是单元格数(即n^2)。 3 个较小的矩阵有n/2 行,这意味着它们有n^2/4 单元格。
  • @Thomash 是的,明白了。我刚刚阅读了帖子下方的cmets。谢谢你的链接..
  • @Thomash 链接坏了,可以重定向吗?
【解决方案4】:

O(log (M * N)) 解对于这个任务是不可能的。

让我们看一个简化的任务:在“已排序”方阵中,假设次对角线(绿色)上方的所有元素都小于给定数,次对角线(红色)下方的所有元素都大于给定数,并且没有额外假设次对角线(黄色)。

这个任务的原始假设和这些额外的假设都没有告诉我们次对角线上的元素是如何相互关联的。这意味着我们只有一个未排序的 N 个整数数组。我们无法比 O(N) 更快地在未排序的数组中找到给定的数字。所以对于方阵的原始(更复杂)问题,我们无法得到比 O(N) 更好的解决方案。

对于矩形矩阵,拉伸正方形图片并相应地设置附加假设。这里我们有 min(N,M) 个大小为 max(N,M)/min(N,M) 的排序子数组。这里最好的搜索方法是使用线性搜索来找到一个或几个可能包含给定值的子数组,然后在这些子数组中使用二分查找。在最坏的情况下,需要在每个子数组中进行二分搜索。复杂度为 O(min(N,M) * (1 + log(max(N,M) / min(N,M))))。因此,对于矩形矩阵的原始(更复杂)问题,我们无法得到比 O(min(N,M) * ( 1 + log(max(N,M)) - log(min(N,M))) 更好的解决方案)。

【讨论】:

  • 很惊讶还没有人在此处发布它,但this 确认了您对复杂性的限制并概述了当时执行的算法。
  • 另外他得到了一个Competence Point
  • 由于我们无法在零时间内解决M==N的情况,所以复杂度应该是O(min(N,M) * (1 + log(max(N,M)) - log(min(N,M))))
  • @hardmath:已修复。谢谢。
【解决方案5】:

我认为这可以在 O(log(n*n)*log(n)) 时间内完成,其中 n 是数字。方阵的行数。

根据Matrix的性质,矩阵的主对角线是一个有序数组。因此,我们可以在 O(log(n)) 中搜索一个元素或其下限。现在,使用这个元素作为枢轴,我们有 4 个子矩阵。我们可以说子矩阵(左上)中的所有元素都较小,子矩阵(右下)中的所有元素都较大。因此,我们可以将其从搜索空间中删除。

现在,在子矩阵(右上)和子矩阵(左下)中递归搜索。

由于我们在每一步都执行 log(n) 次搜索(沿主对角线),因此最多可以有 log(n*n) 步(因为我们在每一步中将搜索空间减少了一半)。

所以,时间复杂度 = O(log(n)log(nn))。

如有错误请指正。

参考 - [书]破解编码面试(问题 11.6)

【讨论】:

    猜你喜欢
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 2014-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-24
    • 2023-01-16
    相关资源
    最近更新 更多