Search a 2D Matrix

Question:

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

  • Integers in each row are sorted from left to right.
  • The first integer of each row is greater than the last integer of the previous row.

For example,

Consider the following matrix:

[

  [1,   3,  5,  7],

  [10, 11, 16, 20],

  [23, 30, 34, 50]

]

Given target = 3, return true.

Solution:

    看到这个题目的第一想法是先对最右边一列做二分查找,定位是在哪一行,然后在这一行做二分查找。时间复杂度是O(logm)+O(logn)=O(logm+logn)=O(log(m*n))。

    这样需要两次二分查找,其实一次就可以了。把二维数组转化为一维数组。从左向右,从上向下依次取出每个元素,那么这些元素是整体有序的,可以看作一个一维数组,用二分查找解决。时间复杂度是O(log(m*n)),和上面的一样。

    开始实现这个二分查找代码的时候,begin和end记录的是两个点,这样代码写起来较复杂,见注释中的代码。后来begin和end改为转化为一维数组后的下标,这样就简单多了。代码如下,在leetcode上测试通过了。

class Solution {

public:

    bool searchMatrix(vector<vector<int> > &matrix, int target) {

        if (matrix.size() == 0)

            return false;

        int col_len = matrix[0].size();

        int row_len = matrix.size();

        int beg = 0;

        int end = row_len * col_len - 1;

        while (beg <= end) {

            int mid = beg + (end - beg) / 2;

            int k = matrix[mid/col_len][mid%col_len];

            if (target == k)

                return true;

            else if (target > k)

                beg = mid + 1;

            else

                end = mid - 1;

        }

        /* 

         * the following is another way, but more complex

         *

        int beg_row = 0;

        int beg_col = 0;

        int end_row = row_len - 1;

        int end_col = col_len - 1;

        while (end_row * col_len + end_col >= beg_row * col_len + beg_col) {

            int total = col_len - beg_col + end_col + 1 + col_len * (end_row - beg_row - 1);

            int k_col = (beg_col + (total / 2) % col_len) % col_len;

            int k_row = beg_row + (beg_col + (total / 2)) / col_len;

            if (target == matrix[k_row][k_col])

                return true;

            else if (target > matrix[k_row][k_col]) {

                beg_row = k_row + (k_col + 1) / col_len;

                beg_col = (k_col + 1) % col_len;

            } else {

                end_row = (k_col == 0) ? k_row - 1 : k_row;

                end_col = (k_col == 0) ? col_len - 1 : k_col - 1;

            }

        }

        */

        return false;

    }

private:

};

    这个题目让我想起了另外一个二维数组题目,二维数组每一行,从左到右有序,每一列,从上到下有序,也是查找一个数。方法是从右上角的元素开始比较大小,指针向下或向左移动,时间复杂度是O(m+n)。

 

你可能感兴趣的:(search)