假设我们有一个大小为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个象限(根据中间行的二进制搜索结果可能有不同的大小),然后我们递归搜索其中两个象限。
答案 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)
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 = 0
或idx = 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=2
、b=4
、f(n)=log(n)/2
和 f(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))
如果两边相同,则等于矩阵的高度或宽度。