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