📌  相关文章
📜  使用分而治之算法在按行和按列排序的二维数组中搜索

📅  最后修改于: 2021-04-29 18:42:26             🧑  作者: Mango

给定一个nxn矩阵,其中每一行和每一列都按升序排序。给定一个键,如何确定该键是否在矩阵中。
在上一篇文章中讨论了线性时间复杂度。这个问题也可能是分而治之算法的一个很好的例子。以下是分而治之的算法。

1)找到中间元素。
2)如果中间元素与键返回相同。
3)如果中间元素小于键,则
….3a)在中间元素下侧搜索子矩阵
….3b)在中间元素右侧搜索子矩阵
4)如果中间元素大于键,则
….4a)在中间元素的左侧搜索垂直子矩阵
….4b)在右侧搜索子矩阵。

DaCMat3

下面实现上述算法。

C++
// C++ program for implementation of 
// divide and conquer algorithm 
// to find a given key in a row-wise 
// and column-wise sorted 2D array
#include
#define ROW 4
#define COL 4
using namespace std;
  
// A divide and conquer method to 
// search a given key in mat[]
// in rows from fromRow to toRow 
// and columns from fromCol to
// toCol
void search(int mat[ROW][COL], int fromRow, int toRow, 
                    int fromCol, int toCol, int key)
    {
        // Find middle and compare with middle 
        int i = fromRow + (toRow-fromRow )/2;
        int j = fromCol + (toCol-fromCol )/2;
        if (mat[i][j] == key) // If key is present at middle
        cout<<"Found "<< key << " at "<< i <<
                            " " << j<= fromCol)
                search(mat, fromRow, toRow, fromCol, j - 1, key);
            }
        }
    }
  
// Driver code
int main()
{
    int mat[ROW][COL] = { {10, 20, 30, 40}, 
                            {15, 25, 35, 45},
                            {27, 29, 37, 48},
                            {32, 33, 39, 50}};
    int key = 50;
    for (int i = 0; i < ROW; i++)
    for (int j = 0; j < COL; j++)
        search(mat, 0, ROW - 1, 0, COL - 1, mat[i][j]);
    return 0;
}
  
// This code is contributed by Rajput-Ji


Java
// Java program for implementation of divide and conquer algorithm 
// to find a given key in a row-wise and column-wise sorted 2D array
class SearchInMatrix
{
    public static void main(String[] args)
    {
        int[][] mat = new int[][] { {10, 20, 30, 40}, 
                                    {15, 25, 35, 45},
                                    {27, 29, 37, 48},
                                    {32, 33, 39, 50}};
        int rowcount = 4,colCount=4,key=50;
        for (int i=0; i=fromCol)
                  search(mat, fromRow, toRow, fromCol, j-1, key);
            }
        }
    }
}


Python3
# Python3 program for implementation of
# divide and conquer algorithm to find 
# a given key in a row-wise and column-wise
# sorted 2D array a divide and conquer method
# to search a given key in mat in rows from 
# fromRow to toRow and columns from fromCol to
# toCol
def search(mat, fromRow, toRow, fromCol, toCol, key):
  
    # Find middle and compare with middle
    i = fromRow + (toRow - fromRow) // 2;
    j = fromCol + (toCol - fromCol) // 2;
    if (mat[i][j] == key): # If key is present at middle
        print("Found " , key , " at " , i , " " , j);
    else:
  
        # right-up quarter of matrix is searched in all cases.
        # Provided it is different from current call
        if (i != toRow or j != fromCol):
            search(mat, fromRow, i, j, toCol, key);
  
        # Special case for iteration with 1*2 matrix
        # mat[i][j] and mat[i][j+1] are only two elements.
        # So just check second element
        if (fromRow == toRow and fromCol + 1 == toCol):
            if (mat[fromRow][toCol] == key):
                print("Found " , key , " at " , fromRow , " " , toCol);
  
        # If middle key is lesser then search lower horizontal
        # matrix and right hand side matrix
        if (mat[i][j] < key):
  
            # search lower horizontal if such matrix exists
            if (i + 1 <= toRow):
                search(mat, i + 1, toRow, fromCol, toCol, key);
  
        # If middle key is greater then search left vertical
        # matrix and right hand side matrix
        else:
              
            # search left vertical if such matrix exists
            if (j - 1 >= fromCol):
                search(mat, fromRow, toRow, fromCol, j - 1, key);
  
# Driver code
if __name__ == '__main__':
    mat = [[ 10, 20, 30, 40],
           [15, 25, 35, 45],
           [27, 29, 37, 48],
           [32, 33, 39, 50]];
    rowcount = 4; colCount = 4; key = 50;
    for i in range(rowcount):
        for j in range(colCount):
            search(mat, 0, rowcount - 1, 0, colCount - 1, mat[i][j]);
  
# This code is contributed by 29AjayKumar


C#
// C# program for implementation of
// divide and conquer algorithm 
// to find a given key in a row-wise 
// and column-wise sorted 2D array
using System;
  
public class SearchInMatrix
{
    public static void Main(String[] args)
    {
        int[,] mat = new int[,] { {10, 20, 30, 40}, 
                                    {15, 25, 35, 45},
                                    {27, 29, 37, 48},
                                    {32, 33, 39, 50}};
        int rowcount = 4, colCount = 4, key = 50;
        for (int i = 0; i < rowcount; i++)
            for (int j = 0; j < colCount; j++)
            search(mat, 0, rowcount - 1, 0, colCount - 1, mat[i, j]);
    }
  
    // A divide and conquer method to 
    // search a given key in mat[]
    // in rows from fromRow to toRow 
    // and columns from fromCol to
    // toCol
    public static void search(int[,] mat, int fromRow, int toRow, 
                            int fromCol, int toCol, int key)
    {
        // Find middle and compare with middle 
        int i = fromRow + (toRow-fromRow )/2;
        int j = fromCol + (toCol-fromCol )/2;
        if (mat[i, j] == key) // If key is present at middle
        Console.WriteLine("Found "+ key + " at "+ i + 
                            " " + j);
        else
        {
            // right-up quarter of matrix is searched in all cases.
            // Provided it is different from current call
            if (i != toRow || j != fromCol)
            search(mat, fromRow, i, j, toCol, key);
  
            // Special case for iteration with 1*2 matrix
            // mat[i][j] and mat[i][j+1] are only two elements.
            // So just check second element
            if (fromRow == toRow && fromCol + 1 == toCol)
            if (mat[fromRow,toCol] == key)
                Console.WriteLine("Found "+ key + " at "+ 
                                fromRow + " " + toCol);
  
            // If middle key is lesser then search lower horizontal 
            // matrix and right hand side matrix
            if (mat[i, j] < key)
            {
                // search lower horizontal if such matrix exists
                if (i + 1 <= toRow)
                search(mat, i + 1, toRow, fromCol, toCol, key);
            }
  
            // If middle key is greater then search left vertical 
            // matrix and right hand side matrix
            else
            {
                // search left vertical if such matrix exists
                if (j - 1 >= fromCol)
                search(mat, fromRow, toRow, fromCol, j - 1, key);
            }
        }
    }
}
  
// This code has been contributed by 29AjayKumar


输出:

Found 10 at 0 0
Found 20 at 0 1
Found 30 at 0 2
Found 40 at 0 3
Found 15 at 1 0
Found 25 at 1 1
Found 35 at 1 2
Found 45 at 1 3
Found 27 at 2 0
Found 29 at 2 1
Found 37 at 2 2
Found 48 at 2 3
Found 32 at 3 0
Found 33 at 3 1
Found 39 at 3 2
Found 50 at 3 3

时间复杂度:
给定一个* n矩阵,该算法可以看做是对大小为n / 2 xn / 2的3个矩阵的重复。以下是时间复杂度的重复

T(n) = 3T(n/2) + O(1) 

复发的解决方案是使用Master方法的O(n 1.58 )。
但是实际的实现需要一个大小为nxn / 2或n / 2 xn的子矩阵,以及另一个大小为n / 2 xn / 2的子矩阵。