二维数组中的二进制搜索

时间:2010-12-12 11:55:09

标签: algorithm multidimensional-array binary-search

我想知道,可以二维搜索应用于二维数组吗?

  • 阵列上的条件是什么?在2D ??
  • 上排序
  • 它的时间复杂性是什么时候?
  • 算法如何改变搜索的边界(minX,maxX,minY,maxY)?

编辑:

1D二进制搜索维护2个指针minXmaxX .. 它选择中间索引(minX+maxX)/2并将其与搜索值进行比较,如果更大则更改maxX,否则更改minX ...直到minX>=maxX

普通二元seacrh的伪代码:

 min := 1;
  max := N; {array size: var A : array [1..N] of integer}
  repeat
    mid := min + (max - min) div 2;
    if x > A[mid] then
      min := mid + 1
    else 
      max := mid - 1;
  until (A[mid] = x) or (min > max);

由于

8 个答案:

答案 0 :(得分:2)

去年我想到了这个问题......所以,我选择了这种方法:

考虑您的2D数组表示平面中的点。例如,元素A [i] [j]表示x = i且y = j的点。要在飞机上使用二进制搜索,我使用以下条件对所有点进行排序:

点p1< p2当且仅当:

  • (p1的x坐标)< (p2的x坐标)
  • (p1的x坐标)=(p2的x坐标)和(p1的y坐标)< (p2的y坐标)

Othwerwise p1> = p2。

现在,如果我们查看2D数组,第2行中的元素应该大于第1行中的元素。在通常排序的相同行元素中(根据其列号)。

换句话说:

  • A [i] [j]> A [k] [j]当且仅当(i> k)。 (在不同的行和同一列中)
  • A [i] [j]> A [i] [k]当且仅当(j> k)。 (在同一行和不同列中)

考虑您的阵列有N行和M列。现在你应该(临时)使用这个公式(T - 临时数组)将你的2D数组转换为1D数组:

for i:=0 to N-1 do
    for j:=0 to M-1 do
        T[i*N + j]:= A[i][j];

现在你有一维数组。按常规方式排序。现在,您可以使用简单的二进制搜索算法进行搜索。

或者您可以使用以下公式将已排序的数组转换回2D数组:

for i:=0 to N*M-1 do
    A[i div N][i - (i div N)*N]:= T[i];

并使用两个二进制搜索:

通过x坐标(我们意义上的行)进行一次搜索,另一次按y坐标(我们意义上的列)搜索同一行中的元素。

换句话说,当您计算mid = mid + (max - min) div 2时,您可以将元素A [mid] [0]与您的键元素(在您的代码中具有 x 名称)进行比较你找到了你的元素的行,你可以在这一行中调用另一个二进制搜索(在A [mid]中进行二进制搜索)。

两种方法的复杂性:

  • 用于在trasformed数组中进行简单的二进制搜索: log(N * M)
  • 用于2D数组中的两个二进制搜索: log(N)用于外部搜索(在行中) + log(M)用于内部搜索(在列中)。< / LI>

使用对数函数的属性,我们可以简化最后一个表达式: log(N)+ log(M)= log(N * M)

因此,我们证明了这两种方法具有相同的复杂性并且无关紧要,哪种方法可以使用。

但是,如果你不难,我建议你简单地将数组转换为1-D并使用简单的二进制搜索(它非常简单,易于调试和检查)。

答案 1 :(得分:1)

二进制搜索以分而治之的方式工作,

int r = arr.length; // ROW Count
int c = arr[0].length; // Column Count
int start = 0; // Initialize with the 0
int end = r*c-1; // Last Index

每次根据要求更新开始索引和结束索引时,我们将继续迭代while循环。     while(开始<=结束){

int mid = (start+end)/2;
int midX = mid/c;
int midY = mid%c;

如果当前值等于搜索元素,那么我们只需要打印并返回它即可。

if(arr[midX][midY] == searchElement){
return true;
}

如果当前值小于搜索元素,那么我们只需将mid值更新为mid = mid + 1

if(arr[midX][midY] < searchElement){
start = mid+1;
}

如果当前值比搜索元素要大,那么我们只需将mid值更新为mid = mid-1

else{
end = mid-1;
}

答案 2 :(得分:1)

这是二进制搜索解决方案,适用于所有测试用例。

bool searchMatrix(vector<vector<int>>& matrix, int target) {
    int h = 0, w = matrix[0].size(), x;
    while(h < matrix.size() && w && (x = matrix[h][w-1]) != target) {
        if (x > target) w--;
        else h++;
    }
    return x == target;
}

答案 3 :(得分:0)

二进制搜索要求对数组进行排序。反过来,排序需要数组元素的总排序关系。在一维中,很容易理解这意味着什么。我认为您必须在二维数组中定义一维索引,并确保数组元素按索引排序。

您有多种一维索引方案可供选择,基本上任何空间填充曲线都可以。想到的显而易见的是:

  • 从第一个元素开始,沿着每一行读取,在每行的末尾转到下一行的第一个元素。
  • 同样,逐行替换。
  • 对角化,依次读取每个对角线。

就像@Bart Kiers一样,我不明白你的第二点。

答案 4 :(得分:0)

如果您的数组按递增值排序,则通过更改A[i][0]在数组i上进行二进制搜索,然后通过更改{{1}在A[i*][j]上进行二进制搜索},其中j是包含所需值的行。

查找i*的方法是:检查i*是否在递增2d数组上(每个给定行的元素都大于),是否期望值位于A[i*][0]A[i*][m]之间。前一个”)。

复杂度应为A[i*][0] < x

答案 5 :(得分:0)

假装它是一维数组,并在分而治之时计算出正确的行和列:

/**
* @param grid {[[number]]} A 2D NxM grid of numbers
* @param targetValue {number} The target value to search
* @return {[number]} A list containing the row and column. For example, [0,5] means row 0 column 5 
*/
function search (grid, targetValue) {
    let rows = grid.length;
    let cols = grid[0].length;

    let leftBound = 0;
    let rightBound = rows * cols - 1;

    while (true) {
        let currentIndex = parseInt((leftBound + rightBound) / 2);
        let currentRow = parseInt(currentIndex / cols);
        let currentColumn = currentIndex % cols;
        let currentValue = grid[currentRow][currentColumn];

        if (currentValue === targetValue) {
            return [currentRow, currentColumn];
        }
        else if (rightBound <= leftBound) {
            return [-1, -1];
        }
        else if (currentValue < targetValue) {
            leftBound = currentIndex + 1;
        }
        else {
            rightBound = currentIndex - 1;
        }
    }

}

search([[11,12,15,23],[25,28,31,32],[35,45,47,47],[50,51,55,56],[65,65,78,88]], 45);

答案 6 :(得分:0)

否,无法在2D数组上应用二进制搜索。

二进制搜索的要求:

要求1:项目已排序

在一维数组中,这很清楚。 但这对2D阵列到底意味着什么?

要求2: 2个方向

二进制搜索要求,只要您在其中选择一个项目,就可以从那里进入2个方向。

由于排序的原因,每当您选择一个项目时,该项目都会提供足够的信息来知道您需要在2个方向中的哪个方向继续搜索。这样可以将搜索范围分为两部分,这就是为什么我们称其为二进制。

如果您选择2D阵列中的项目,则有4个可能的方向(甚至更多:您也可以对角移动)。即使所有项目都以某种方式排序,一项中的信息也无法告诉您必须走哪个方向以及如何基于该方向拆分数组。

仅当您可以将2D数组转换为排序的1D数组时,才可以进行二进制搜索。 如果可以定义一个将索引x和y合并为索引i的函数,以对包含2D数组中所有项的已排序虚拟1D数组进行索引,并且可以从i返回x和y,则可以在该索引上使用二进制搜索虚拟一维阵列。该功能取决于2D数组中项目的排序方式。但这意味着您要在1D数组而不是2D数组上执行二进制搜索!

答案 7 :(得分:-1)

您可以将2D数组转换为1D数组并在此处进行二进制搜索。 O(log(m * n))数组的复杂度为mxn