搜索排序矩阵的复杂性

时间:2015-07-26 06:17:21

标签: algorithm matrix time-complexity

假设我们有一个大小为NxN的数字矩阵,其中所有的行和列按递增顺序排列,我们想要查找它是否包含值v。一种算法是在中间行执行二进制搜索,找到与v最接近的元素:M [row,col]< v< M [row,col + 1](如果我们确切地找到v,则搜索完成)。由于矩阵是有序的,我们知道v大于子矩阵M [0..row,0..col](矩阵的左上象限)中的所有元素,并且类似地它更小比子矩阵M [row..N-1,col + 1..N-1](右下象限)中的所有元素。因此我们可以递归搜索右上象限M [0..row-1,col + 1..N-1]和左下象限M [row + 1..N-1,0..col]。

问题是这个算法的复杂性是什么?

示例:假设我们有5x5矩阵,如下所示,我们正在搜索数字25:

0 10 20 30 40
1 11 21 31 41
2 12 22 32 42
3 13 23 33 43
4 14 24 34 44

在第一次迭代中,我们对中间行执行二分查找,并找到小于25的最接近元素是22(在行= 2 col = 2)。所以现在我们知道25大于左上角3x3象限中的所有项目:

0 10 20
1 11 21
2 12 22

类似地,我们知道25小于右下3x2象限中的所有元素:

32 42
33 43
34 44

所以,我们递归搜索剩下的象限 - 右上角2x2:

30 40
31 41

和左下角2x3:

3 13 23
4 14 24

等等。我们基本上将矩阵划分为4个象限(根据中间行的二进制搜索结果可能有不同的大小),然后我们递归搜索其中两个象限。

6 个答案:

答案 0 :(得分:2)

最坏情况下的运行时间是Theta(n)。当然,这与正确的算法一样好(考虑反对角线,元素小于v以上,元素大于v)。就上限而言,n行,m列矩阵的界限为O(n log(2 + m / n)),正确的复发证明

                  m-1
f(n, m) = log m + max [f(n/2, j) + f(n/2, m-1 - j)],
                  j=0

哪里有两个子问题,而不是一个。这种复发可通过替代方法解决。

        ?
f(n, m) ≤ c n log(2 + m/n) - log(m) - 2  [hypothesis; c to be chosen later]

                  m-1
f(n, m) = log m + max [f((n-1)/2, j) + f((n-1)/2, m-j)]
                  j=0

                    m-1
        ≤   log m + max [  c (n/2) log(2 + j/(n/2)) - log(j) - 2
                         + c (n/2) log(2 + (m-j)/(n/2))] - log(m-j) - 2]
                    j=0

        [fixing j = m/2 by the concavity of log]

        ≤ log m + c n log(2 + m/n) - 2 log(m/2) - 4

        = log m + c n log(2 + m/n) - 2 log(m) - 2

        = c n log(2 + m/n) - log(m) - 2.

将c设置得足够大,对于所有n,m,

c n log(2 + m/n) - log(m) - 2 ≥ log(m),

其中log(m)是基本情况的成本n = 1.

答案 1 :(得分:1)

该算法的复杂性为 - :

  

为O(log <子> 2 (N * N))       = O(log 2 (n))

这是因为你在一次迭代中消除了一半的矩阵

编辑 - :

递归关系 - :

假设n是矩阵中元素的总数,

=&GT; T(n) = T(n/2) + log(sqrt(n))
=&GT; T(n) = T(n/2) + log(n^(1/2))
=&GT; T(n) = T(n/2) + 1/2 * log(n)

此处,a = 1,b = 2。 因此,c = log b (a)= log 2 (1)= 0
=&GT; n^c = n^0
另外,f(n) = n^0 * 1/2 * log(n)

根据case 2 of Master Theorem

T(n) = O((log(n))^2)

答案 2 :(得分:0)

我们假设我们有以下矩阵:

1 2 3
4 5 6
7 8 9

让我们按照您的指定使用二进制搜索搜索值7

在中间行搜索最接近7的值:4 5 6,即6。 嗯我们有问题,7不在以下子矩阵中:

6
9

那该怎么办?一种解决方案是将二进制搜索应用于所有行,其复杂度为nlog(n)。因此,走矩阵是一个更好的解决方案。

编辑:

递归关系:

T(N*N) = T(N*N/2) + log(N)

如果我们使用M = N^2将函数规范化为一个变量:

T(M) = T(M/2) + log(sqrt(M))
T(M) = T(M/2) + log(M)/2

根据Master Theorem Case#2,复杂性是

(log(M))^2
=> (2log(N))^2
=> (log(N))^2

编辑2:

抱歉,我从手机上回答了你的问题,现在当你想到它时,M[0...row-1, col+1...N-1]没有多大意义吗?考虑一下我的例子,如果你搜索的值小于中间行中的所有值,你总会得到最左边的数字。同样,如果搜索的值大于中间行中的所有值,则最终会得到最右边的数字。所以算法可以改写如下:

  

使用自定义二进制搜索搜索中间行,如果找到则返回1 <= idx <= N,如果找不到,则返回idx = 0idx = N+1。二进制搜索后idx = 0,在上部子矩阵中开始搜索:M[0...row][0...N]。   如果索引为N + 1,则在较低的子矩阵中开始搜索:M[row+1...N][0...N]。否则,我们就完成了。

您建议复杂性应为:2T(M/4) + log(M)/2。但是在每一步,我们将整个矩阵除以两个,只处理其中一个。 此外,如果您同意T(N*N) = T(N*N/2) + log(N)是正确的,那么您可以用N*N替换所有M个表达式。

答案 3 :(得分:0)

如果在n步之后找到元素,则可搜索范围的大小为N = 4 ^ n。然后,时间复杂度为O(N的对数基数为4)= O(log N / log 4)= O(0.5 * log N)= O(log N)。

换句话说,您的算法比二分搜索快两倍,等于O(log N)

答案 4 :(得分:0)

对矩阵二进制搜索的考虑:

2D矩阵和一般ND矩阵进行二进制搜索与对已排序的1D向量进行二分搜索没有什么不同。例如,Infact C以行主要方式存储它们(作为行的连续来自:[[row0],[row1] .. [rowk]] 这意味着可以在矩阵上使用众所周知的二进制搜索(具有复杂性log(n*m)):

template<typename T>
bool binarySearch_2D(T target,T** matrix){
    int a=0;int b=NCELLS-1;//ROWS*COLS
    bool found=false;
    while(!found && a <= b){
        int half=(a+b)/2;
        int r=half/COLS;
        int c=half-(half/COLS)*COLS;
        int v =matrix[r][c];
        if(v==target)
            found=true;
        else if(target > v)
            a=half+1;
        else //target < v
            b=half-1;
    }
    return found;
}

答案 5 :(得分:0)

您可以使用递归函数并应用主定理来求复杂度。

假设 n 是矩阵中的元素数。 一步的成本是对 sqrt(n) 元素进行二分搜索,你会遇到两个问题,在最坏的情况下,每个元素大小相同,有 n/4 个元素:2*T(n/4)。所以我们有:

T(n)=2*T(n/4)+log(sqrt(n))

等于

T(n)=2*T(n/4)+log(n)/2

现在应用 master theorem 案例 1(a=2b=4f(n)=log(n)/2f(n) in O(n^log_b(a))=O(n^(1/2)) 因此我们有案例 1)

=> 总运行时间 T(n)O(n^(a/b)) = O(n^(1/2))

或等于

O(sqrt(n))

如果两边相同,则等于矩阵的高度或宽度。