在sortingmatrix(行n列)中查找O(log n)

说我有一个matrix( MxN )的行和列sorting。

  1. 每一行中的所有元素按照递增顺序排列
  2. 每列中的所有元素都按照顺序排列
  3. 所有元素都是整数
  4. 没有其他假设可以做出

    例:

    [1 5 8 20]

    [2 9 19 21]

    [12 15 25 30]

我必须find一个给定的数字是否存在于matrix中(基本search)。 我有一个algorithm运行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))解决scheme。 有任何想法吗??

O(log(M * N))解决scheme不适用于此任务。

让我们来看一个简化的任务:在“sorting”matrixmatrix中,假设所有高于次对angular线(绿色)的元素都小于给定数目,次对angular线(红色)以下的所有元素大于给定数目,并且对于次对angular线黄色)。

在这里输入图像说明

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

对于矩形matrix,拉伸正方形图片并相应地设置其他假设。 这里我们有min(N,M)个大小分别为max(N,M)/ min(N,M)的子数组。 在这里search的最好方法是使用线性search来查找可能包含给定值的一个或多个子数组,然后在这些子数组内使用二进制search。 在最坏的情况下,需要在每个子arrays中进行二进制search。 复杂度为O(min(N,M)*(1 + log(max(N,M)/ min(N,M))))。 因此对于矩形matrix的原始(更复杂)问题,我们不能得到比O(min(N,M)*(1 + log(max(N,M)) – log(min(N,M))) )。

不可能比O(n)做得更好。 有些人(这个页面上至less有三个人)认为他们可以做得更好,但是这是因为他们的algorithm是错误的,或者因为他们不知道如何计算algorithm的复杂性,所以他们试图猜测它。 这个博客文章非常好,会向你解释这些人的错误。

O(n)是最优的certificate草案:考虑以下matrix:

 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) 

如果你在这个matrix中查找n ,那么如果n在行中,那么每行至less应该检查一次,因为n可以在任何行中。 (certificate不完整,但这是主意)

你必须使用recursion来解决这个问题。 给定matrixX和数字Y,可以在X的中间行进行二分search,并将matrix分成四部分:

 A|B --- C|D 

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

由于高度(A)=高度(B)\高度(C)=高度(D),尺寸(X)> = 2 *(尺寸(B)+尺寸(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 ) 

由于行和列都是sorting的,所以如果我们查看每一行的第一个元素,我们可以find哪一个包含我们要查找的数字。 然后,再次,我们可以利用每行中的元素进行sorting并find该数字的事实。
我所知道的最快的searchalgorithm是二进制search,其复杂度为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)的元素进行二分search,发现该行是第三行,因为它的第一个元素小于我们的数字, 下一行的第一个元素更大。 步数:2 (21,31,find)
  • 我们在第三行(21,22,23,24,25,26,27,28,29,30)再次进行二分search,find我们的号码。 步数:2 – 3 (25,27或28,find)

我认为这可以在O(log(n * n)* log(n))时间完成,其中n是否。 正方形matrix的行。

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

现在,在子matrix(右上)和子matrix(左下)中进行recursionsearch。

因为在每一步,我们执行log(n)search(沿着主对angular线)广告可以有最近的log(n * n)步骤(因为我们在每一步中减less了一半的search空间)。

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

如有任何错误,请纠正。

Refrences – [图书]破解编码面试(问题11.6)