力扣 74 搜索二维矩阵【二分法】【边界确定】
全部刷题与学习记录
原题目
题目地址:74. 搜索二维矩阵
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
示例 1:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:true
示例 2:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
输出:false
考查知识点
二分法,二分法兴趣区间开闭,二分法区间更新
自己的第一遍解法
思路是有了,根据数组特点,每一行每一列都是升序排列即非递减序列。
- 用两次二分法,第一次二分所有行(实际是二分所有行的第一列数字),找到最接近target但仍小于target的那一行;
- 第二次二分第一步找到这一行的所有列,直到找到target的数字或者左右端点交错(left>right,说明没有等于target的数字)
从 【算法套路】-【二分法】【左右端点的更新】 中知道二分法对于兴趣区间的开闭有两种:左闭右闭、左闭右开。
这里我们选择 左闭右闭[left, right],二分查找的过程倒是没有问题了,但是怎么在二分过程中根据条件退出呢?
好的解法
参考:力扣题解 的评论区
直接上程序,后面写分析
class Solution {
public:
bool searchMatrix(vector<vector<int>> matrix, int target) {
int m = matrix.size();
int n = matrix[0].size();
int left = 0, right = m - 1;
// 二分查找:在第0列中二分,找到小于target的最接近的元素,记录行号row
int row = 0;
while (left <= right) {
int mid = left + (right - left) / 2;
int cur = matrix[mid][0];
if (cur == target) return true;
else if (cur < target) {
row = mid;
left = mid + 1;
} else {
// cur > target
right = mid - 1;
}
}
// 二分查找:在第row行中二分,找target是否存在
left = 1;
right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
int cur = matrix[row][mid];
if (cur == target) return true;
else if (cur < target) left = mid + 1;
else right = mid - 1;
}
return false;
}
};
【分析】:在二分所有行的过程中,通过row
来记录小于target并最接近target的行,关键就是在cur(mid行首元素)<target
的条件下,将row
更新为最新的mid
,因为row的定义是最接近target并且小于target的值
我们不妨用个简单例子来看看left
mid
right
和row
的更新关系:
假设数组为:
1 2 3
4 5 6
7 8 9
10 11 12
对应的left mid right
0 1 3
2 2 3
3 3 3
在此过程中,row只有两次赋值过程,分别是left=0时与left=1时,因为left=3时,matrix[3][0]已经大于target
在上面例子中,left=3时不会更新row,并且在下一步更新了right后因不满足循环条件(left=3,right=2)而退出循环
在二分所有列的过程中,情况与上面相同,只不过这次不用记录什么东西,退出循环的条件只有两个:找到target、左右交错(left>right)