搜索排序矩阵的最有效方法是什么?

时间:2010-11-09 20:04:15

标签: language-agnostic search matrix big-o time-complexity

我有一个编写算法(不是任何特定语言,只是伪代码)的赋值,它接收一个矩阵[size:M x N],该矩阵的排序方式是所有行的排序和全部它的列是单独排序的,并在此矩阵中找到一个特定的值。我需要编写我能想到的最节省时间的算法。

矩阵看起来像:

1  3  5
4  6  8
7  9 10

我的想法是从第一行和最后一列开始,只需检查值,如果它更大,那么它是否小于左边并继续这样做,直到找到该值或直到索引超出范围(如果该值不存在)。该算法在线性复杂度O(m + n)下工作。我被告知有可能以对数复杂度这样做。可能吗?如果是的话,怎么样?

9 个答案:

答案 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个相等的部分,则此属性是递归的。

所以我们可以尝试使用二进制搜索:

  1. 探索价值,
  2. 分成几部分,
  3. 选择正确的作品(不知何故),
  4. 转到新作品1。
  5. 因此算法可能如下所示:

    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)

这是错误的答案

我真的不确定是否有任何答案是最佳答案。我正在努力。

  1. 二元搜索第一行和第一列,找出“x”所在的行和列。你会得到0,j和i,0。如果在此步骤中找不到x,则x将位于i行或j列上。
  2. 对您在步骤1中找到的第i行和第j列进行二进制搜索。
  3. 我认为时间复杂度是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;

}
相关问题