题目描述
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
示例 1:
输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5
输出:true
示例 2:
输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20
输出:false提示:
m == matrix.length
n == matrix[i].length
1 <= n, m <= 300
-109 <= matrix[i][j] <= 109
每行的所有元素从左到右升序排列
每列的所有元素从上到下升序排列
-109 <= target <= 109
果果念
这道题目是一道面试真题,在lc上看到的。我是第一次做,二分法是很容易想到的。在lc平台上,复杂度为O(mlogn),只超过了10%左右的C++提交者。可以仔细分析一下,二分法只利用了一个性质 ,就是看你按照行进行二分穷举各列,还是按照列进行二分穷举各行了,反正总体来说,没有同时顾及行列有序的性质,因此有更优化的方法。
“Z字型”扫描法,暂且这样叫它吧。这各方法的巧妙之处在于如果我们在矩阵的右上方遍历,一直到左下方,那么按行来说,数值越来越小,按列来说,数值越来越大。现在可以明白了吧,因为如果常规从坐上遍历的话,往下、往右都是递增的。但是左下方遍历就不一样,如果当前值小于target,那么row++;如果当前值大于target,那么col--;最后注意一下边界条件即可,真的好巧妙啊!让我们来计算一下这个的复杂度,O(m+n),天哪,太棒了吧~
//二分法
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
//二分查找 中间的一行中间值
for(int i=0;i<matrix.size();i++){
if(binarySearch(matrix,i,0,matrix[i].size()-1,target)==true){
return true;
}
}
return false;
}
bool binarySearch(vector<vector<int>>& matrix,int row,int left,int right,int target){
if(right<left) return false;
int mid=(left+right)/2;
if(matrix[row][mid]==target){
return true;
}else if(matrix[row][mid]<target){
return binarySearch(matrix,row,mid+1,right,target);
}else{
//matrix[row][mid]>target
return binarySearch(matrix,row,left,mid-1,target);
}
}
};
//Z字形查找
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
//Z字形查找
int m=matrix.size(),n=matrix[0].size();
int row=0,col=n-1;
while(row<m&&col>=0){
if(matrix[row][col]==target){
return true;
}else if(matrix[row][col]<target){
row++;
}else {//matrix[row][col]>target
col--;
}
}
return false;
}
};