题目描述
枚举
枚举整个矩阵,找到等于 target
的元素,则 return true
,否则 return false
。
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int n = matrix.size(), m = matrix[0].size();
for (auto &x : matrix)
for (auto &t : x)
if (t == target) return true;
return false;
}
};
- 时间复杂度 : O ( n × m ) O(n\times m) O(n×m) , n n n 是数组的行数, m m m 是数组的列数,枚举所有元素,时间复杂度 O ( n × m ) O(n\times m) O(n×m) 。
- 空间复杂度 : O ( 1 ) O(1) O(1) , 只使用常量级空间 。
二分查找
二分优化枚举。按行枚举矩阵,由于每行元素有序,可以二分查找行内的元素。
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int n = matrix.size(), m = matrix[0].size();
for (auto &x : matrix) {
int l = 0, r = m - 1;
while(l <= r) {
int mid = l + (r - l >> 1);
if (x[mid] < target) l = mid + 1;
else r = mid - 1;
}
if (l < m && x[l] == target) return true;
}
return false;
}
};
- 时间复杂度 : O ( n l o g m ) O(nlogm) O(nlogm) , n n n 是数组的行数, m m m 是数组的列数,一次枚举一行,每行二分查找,时间复杂度 O ( n l o g m ) O(nlogm) O(nlogm) 。
- 空间复杂度 : O ( 1 ) O(1) O(1) , 只使用常量级空间 。
枚举行列
更大胆的,同时枚举行列。这是由于每行元素有序,每列元素同样有序。
目的:保证被枚举元素与 target
的大小关系,对应唯一的移动方向
结论:从右上角枚举到左下角,根据右上角元素与 target
的大小关系,确定枚举的移动方向。
证明:右上角元素是一行的最大元素,一列的最小元素。往左下枚举,要找比他小的元素,只能同行往左;要找比他大的元素,只能同列向下。即
右上角元素
>
\gt
> target
,往左;右上角元素
<
\lt
< target
,往下。
朴素错法
- 为什么从左上角枚举到右下角不行?
答:左上角元素是一行的最小元素,一列的最小元素。往右下枚举,要找比他大的元素,不能确定往右还是往下。
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int n = matrix.size(), m = matrix[0].size();
int i = 0, j = m - 1;
while(i < n && j >= 0) {
if (matrix[i][j] > target) j --;
else if (matrix[i][j] < target) i ++;
else return true;
}
return false;
}
};
- 时间复杂度 : O ( n + m ) O(n+m) O(n+m) , n n n 是数组的行数, m m m 是数组的列数,一次枚举,移动一列或者一行,时间复杂度 O ( n + m ) O(n+m) O(n+m) 。
- 空间复杂度 : O ( 1 ) O(1) O(1) , 只使用常量级空间 。
AC
按行列枚举,执行结果。
致语
- 理解思路很重要
- 读者有问题请留言,清墨看到就会回复的。