在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:
现有矩阵 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
。
给定 target = 20
,返回 false
。
限制:0 <= n <= 1000
,0 <= m <= 1000
介绍一下三种方法:
法一:分治
这是我自己做的时候用的方法,因为学校里算法课上讲过类似的题,记忆犹新。题目中的矩阵有一个性质:对于某一元素,其右上的数都比它小,左下的都比它大。由此,若我们将 target 和某数(中心)比较,则可以排除矩阵中约 4/1 的元素(左下或右上)。
时间复杂度:
👆 target比9大排除红框,比9小排除蓝框
class Solution {
public:
//在[rangeX1~rangeX2][rangeY1~rangeY2]范围内搜索
bool searchA(vector<vector<int>>& matrix, int target,int rangeX1,int rangeX2,int rangeY1,int rangeY2){
//递归中止
if(rangeX1>rangeX2||rangeY1>rangeY2){
return false;
}
//计算中心位置(c_x,c_y)
int c_x=(rangeX1+rangeX2)/2;
int c_y=(rangeY1+rangeY2)/2;
//递归,三部分的结果分别为p1,p2,p3
bool p1,p2,p3;
if(matrix[c_x][c_y]==target){
return true;
}else if(matrix[c_x][c_y]<target){
p1=searchA(matrix,target,rangeX1,c_x,c_y+1,rangeY2);//右上
p2=searchA(matrix,target,c_x+1,rangeX2,c_y+1,rangeY2);//右下
p3=searchA(matrix,target,c_x+1,rangeX2,rangeY1,c_y);//左下
}else{
p1=searchA(matrix,target,rangeX1,c_x-1,c_y,rangeY2);//右上
p2=searchA(matrix,target,rangeX1,c_x-1,rangeY1,c_y-1);//左上
p3=searchA(matrix,target,c_x,rangeX2,rangeY1,c_y-1);//左下
}
return p1||p2||p3;
}
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
if(matrix.size()==0||matrix[0].size()==0){return false;}
int n=matrix.size(),m=matrix[0].size();
return searchA(matrix,target,0,n-1,0,m-1);
}
};
法二:
写完看了下耗时最短的,居然用的是每行分别二分,我不理解。也许是人家代码写得漂亮hh
时间复杂度:O(n*log(m))
//**转载
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
//每行进行二分查找
for (const auto& row: matrix) {
auto it = lower_bound(row.begin(), row.end(), target); //标记第一个不小于value 的值位置
if (it != row.end() && *it == target) {
return true;
}
}
return false;
}
};
法三(转自官方题解):
由于给定的二维数组具备每行从左到右递增以及每列从上到下递增的特点,当访问到一个元素时,可以排除数组中的部分元素。
从二维数组的右上角开始查找。如果当前元素等于目标值,则返回 true。如果当前元素大于目标值,则移到左边一列。如果当前元素小于目标值,则移到下边一行。
可以证明这种方法不会错过目标值。如果当前元素大于目标值,说明当前元素的下边的所有元素都一定大于目标值,因此往下查找不可能找到目标值,往左查找可能找到目标值。如果当前元素小于目标值,说明当前元素的左边的所有元素都一定小于目标值,因此往左查找不可能找到目标值,往下查找可能找到目标值。
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/solution/mian-shi-ti-04-er-wei-shu-zu-zhong-de-cha-zhao-b-3/
来源:力扣(LeetCode)
(感觉比较巧妙)