审题
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
示例 1:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,50]], target = 3
输出:true
示例 2:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,50]], target = 13
输出:false
示例 3:
输入:matrix = [], target = 0
输出:false
提示:
m == matrix.length
n == matrix[i].length
0 <= m, n <= 100
-10^4 <= matrix[i][j], target <= 10^4
看到这道题,首先想到用二分,然而,却有可能对于一些数的判断和边界条件产生不同的影响,实现起来细节较多,多次WA之后,好歹算是AC了,但是代码依旧不尽人意,具体实现方法是先用二分查找看待寻找数据在哪行,再用二分查找在该行找到该数。
代码实现
方案一(上文提到的方法):
WA了好几次,有蒙的嫌疑,大家看个乐呵就行。
class Solution {
public:
int find_row(vector<vector<int>>& matrix, int target) {
int l=0;
int r=matrix.size()-1;
int mid;
if ( r == 0 ) return 0;
while ( l<=r ) {
mid = l + (r-l)/2;
if ( target == matrix[mid][0] ) return mid;
if ( target < matrix[l][0] ) return (l-1)<0?0:l-1;
if ( target > matrix[r][0] ) return r;
if ( target > matrix[mid][0] ) l = mid + 1;
else r = mid - 1;
}
return -1;
}
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if ( matrix.size() == 0 ) return false;
if ( matrix[0].size() == 0 ) return false;
int l=0;
int r=matrix[0].size()-1;
int mid;
int row = find_row(matrix, target);
while ( l<=r ) {
mid = l + (r-l)/2;
if ( matrix[row][mid] == target ) return true;
if ( matrix[row][mid] < target ) l = mid+1;
else r = mid-1;
}
return false;
}
};
方案2(一维数组):
呜呜呜,我怎么那么菜啊,二维数组完全可以当作一维数组来从左往右找,这就是最基本的二分查找,下次还是要好好想想数据结构,这也太顶了。换个数据结构秒变简单题:
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size();
if ( m == 0 ) return false;
int n = matrix[0].size();
int l=0;
int r=m*n-1;
int mid;
while ( l<=r ) {
mid = l + (r-l)/2;
if ( matrix[mid/n][mid%n] == target ) return true;
if ( matrix[mid/n][mid%n] > target ) r = mid-1;
else l = mid+1;
}
return false;
}
};
反思
这道题的话,看出来了审题的重要性吧还是,好好审题比啥都强,这道题的难度一般,一维数组确实是挺巧的,学习了,巧巧巧。