我有一个编写算法(不是任何特定语言,只是伪代码)的赋值,它接收一个矩阵[size:M x N],该矩阵的排序方式是所有行的排序和全部它的列是单独排序的,并在此矩阵中找到一个特定的值。我需要编写我能想到的最节省时间的算法。
矩阵看起来像:
1 3 5
4 6 8
7 9 10
我的想法是从第一行和最后一列开始,只需检查值,如果它更大,那么它是否小于左边并继续这样做,直到找到该值或直到索引超出范围(如果该值不存在)。该算法在线性复杂度O(m + n)下工作。我被告知有可能以对数复杂度这样做。可能吗?如果是的话,怎么样?
答案 0 :(得分:4)
你的矩阵看起来像这样:
a ..... b ..... c
. . . . .
. 1 . 2 .
. . . . .
d ..... e ..... f
. . . . .
. 3 . 4 .
. . . . .
g ..... h ..... i
并具有以下属性:
a,c,g < i
a,b,d < e
b,c,e < f
d,e,g < h
e,f,h < i
因此,最低角度的最大角落(例如i
)中的值始终是整个矩阵中最大的
如果将矩阵分成4个相等的部分,则此属性是递归的。
所以我们可以尝试使用二进制搜索:
因此算法可能如下所示:
input: X - value to be searched
until found
divide matrix into 4 equal pieces
get e,f,h,i as shown on picture
if (e or f or h or i) equals X then
return found
if X < e then quarter := 1
if X < f then quarter := 2
if X < h then quarter := 3
if X < i then quarter := 4
if no quarter assigned then
return not_found
make smaller matrix from chosen quarter
这就像O(log n)那样找我,其中n是矩阵中元素的数量。它是一种二元搜索,但是在两个维度上。我不能正式证明它,但类似于典型的二元搜索。
答案 1 :(得分:2)
那是样本输入的样子吗?对角线排序?可以肯定的是,这是一种有趣的方式。
由于以下行的值可能低于此行上的任何值,因此您无法对给定的数据行进行任何特定的处理。
我会(如果要求在大输入上执行此操作)将矩阵读入list-struct,将数据作为一对元组,并将mxn coord作为元组的一部分,然后快速排序矩阵一次,然后按值找到它。
或者,如果每个单独位置的值是唯一的,则将MxN数据抛入键入该值的字典中,然后根据输入的键(或键的哈希值)跳转到MxN的字典条目输入)。
编辑:
请注意,如果您要多次查看矩阵,我上面给出的答案是有效的。如果你只需要解析一次,那么这就像你能做到的那样快:
for (int i = 0; i<M; i++)
for (int j=0; j<N; j++)
if (mat[i][j] == value) return tuple(i,j);
显然我对这个问题的评论也应该在这里:|
@sagar但这不是教授给出的例子。否则他有上面最快的方法(首先检查行的结尾然后继续),另外,首先检查中间行的结尾会更快,有点二进制搜索。
检查每一行的结尾(并从中间行的末尾开始)找到一个高于内存数组中已检查数字的数字将是最快的,然后在每个匹配的行上进行二进制搜索,直到你找到它。
答案 2 :(得分:2)
在log M中,您可以获得一系列能够包含目标的行(对行的第一个值进行二进制搜索,对行的最后一个值进行二进制搜索,仅保留第一个&lt; = target和last&gt;的行) = target)两个二进制搜索仍为O(log M)
然后在O(log N)中,你可以探索这些行中的每一行,再次进行二分搜索!
使其成为O(logM x logN)
tadaaaa
答案 3 :(得分:0)
public static boolean find(int a[][],int rows,int cols,int x){
int m=0;
int n=cols-1;
while(m<rows&&n>=0){
if(a[m][n]==x)
return1;
else if(a[m][n]>x)
n--;
else m++;
}
}
答案 4 :(得分:0)
这是错误的答案
我真的不确定是否有任何答案是最佳答案。我正在努力。
我认为时间复杂度是2 *(log m + log n)。
如果输入数组是方形(n * n),则可以通过沿对角线的二进制搜索来减小常量。
答案 5 :(得分:0)
如何获得对角线,然后在对角线上进行二元搜索,从右下角开始检查它是否在上面,如果是,则将对角线阵列位置作为它所在的列,如果不是,则检查它是否在下面。一旦你在对角线上击中(使用对角线的数组位置作为列索引),每次在列上运行二进制搜索。我认为这是@ user942640
所述的内容你可以得到上面的运行时间,并在需要时(在某些时候)交换算法在初始对角线阵列上进行二分搜索(这是考虑到它的n * n个元素并获得x或y长度是O(1)为x.length = y.length。即使在百万*百万二进制搜索对角线,如果它少于半步后退对角线,如果它不小于二进制搜索回到你在哪里(这是沿着对角线进行二元搜索时算法的一个小改动。我认为对角线比行中的二元搜索更好,我只是为了看看数学时的疲惫:))
顺便说一下,我认为运行时间与你在最佳/最差/平均情况和时间对内存大小等方面所描述的分析略有不同,所以问题会更好地说明'什么是最好的在最坏情况分析中的运行时间',因为在最好的情况下,你可以做一个粗暴的线性扫描,项目可能在第一个位置,这将比二进制搜索更好'运行时间'......
答案 6 :(得分:0)
这是 n 的下限。从未排序的数组A开始,长度为 n 。根据以下规则构造新矩阵M:次要对角线包含阵列A,其上方的所有内容均为负无穷大,其下方的所有内容均为无穷大。对行和列进行排序,在M中查找条目与在A中查找条目相同。
答案 7 :(得分:0)
这是Michal's answer的静脉(从中我将窃取漂亮的图形)。
矩阵:
min ..... b ..... c
. . .
. II . I .
. . .
d .... mid .... f
. . .
. III . IV .
. . .
g ..... h ..... max
最小值和最大值分别是最小值和最大值。 &#34;中间&#34;不一定是平均值/中位数/任何值。
我们知道mid的值是&gt; =象限II中的所有值,&lt; =象限IV中的所有值。我们不能对象限I和III提出这样的要求。如果我们递归,我们可以在每个级别消除一个象限。
因此,如果目标值小于mid,我们必须搜索象限I,II和III。如果目标值大于mid,我们必须搜索象限I,III和IV。
每个步骤的空间减少到之前的3/4:
n *(3/4) x = 1
n =(4/3) x
x = log 4/3 (n)
对数因常数因子而不同,因此这是O(log(n))。
find(min, max, target)
if min is max
if target == min
return min
else
return not found
else if target < min or target > max
return not found
else
set mid to average of min and max
if target == mid
return mid
else
find(b, f, target), return if found
find(d, h, target), return if found
if target < mid
return find(min, mid, target)
else
return find(mid, max, target)
答案 8 :(得分:0)
JavaScript解决方案:
//start from the top right corner
//if value = el, element is found
//if value < el, move to the next row, element can't be in that row since row is sorted
//if value > el, move to the previous column, element can't be in that column since column is sorted
function find(matrix, el) {
//some error checking
if (!matrix[0] || !matrix[0].length){
return false;
}
if (!el || isNaN(el)){
return false;
}
var row = 0; //first row
var col = matrix[0].length - 1; //last column
while (row < matrix.length && col >= 0) {
if (matrix[row][col] === el) { //element is found
return true;
} else if (matrix[row][col] < el) {
row++; //move to the next row
} else {
col--; //move to the previous column
}
}
return false;
}