代码改变世界

Search a 2D Matrix

2015-03-10 14:54  李涛的技术博客  阅读(284)  评论(0编辑  收藏  举报

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)。