LeetCode 240. Search a 2D Matrix II
编写一个高效的算法来搜索 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.lengthn == matrix[i].length1 <= n, m <= 300-109 <= matrix[i][j] <= 109- 每行的所有元素从左到右升序排列
- 每列的所有元素从上到下升序排列
-109 <= target <= 109
算法1
(二分) O(k(logn+logm))
始化上下左右边界 up, down, left, right,保证 target 可能出现在此区域。
每次在 up 行中,二分求出新的 right;在 down 行中,二分求出新的 left;
接着在 2 求出的 left 列中,二分求出新的 down;在 2 求出的 right 列中,二分求出新的 up;
如果 up == down && left == right,则判断 matrix[up][left] == target。
注意,如果一轮迭代更新中,四个元素的值都没有变化,则说明那一片区域有多个 target,直接返回 true。
时间复杂度
每次迭代时间复杂度为 O(logn+logm),假设需要 k次迭代,故时间复杂度为 O(k(logn+logm))。
最坏情况可能 k=min(n,m),但平均情况下很难达到最坏情况。
空间复杂度
仅需要常数的额外空间。
AC 代码
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();
if (n == 0)
return false;
int up = 0, down = m - 1, left = 0, right = n - 1;
int l, r;
while (up < down || left < right) {
int new_left, new_right, new_up, new_down;
/*********************/
l = left; r = right;
while (l < r) {
int mid = (l + r) >> 1;
if (target >= matrix[up][mid + 1])
l = mid + 1;
else
r = mid;
}
new_right = l;
/*********************/
/*********************/
l = left; r = right;
while (l < r) {
int mid = (l + r) >> 1;
if (target <= matrix[down][mid])
r = mid;
else
l = mid + 1;
}
new_left = l;
/*********************/
/*********************/
l = up; r = down;
while (l < r) {
int mid = (l + r) >> 1;
if (target >= matrix[mid + 1][new_left])
l = mid + 1;
else
r = mid;
}
new_down = l;
/*********************/
/*********************/
l = up; r = down;
while (l < r) {
int mid = (l + r) >> 1;
if (target <= matrix[mid][new_right])
r = mid;
else
l = mid + 1;
}
new_up = l;
/*********************/
if (left == new_left && right == new_right && up == new_up && down == new_down)
return true;
up = new_up;
down = new_down;
left = new_left;
right = new_right;
}
return matrix[up][left] == target;
}
};
算法2
(单调性扫描) O(n+m)
初始化 up = 0,right = n - 1,从右上角元素开始。
如果发现 matrix[up][right] == target,则直接返回 true;
若 matrix[up][right] < target,则向下移动 up++;
否则,向左移动 right--;
如果出界返回 false。
时间复杂度
可以看到每次 up 向下移动或者 right 向左移动,移动次数不超过 n+m 次,故时间复杂度为 O(n+m)。
AC 代码
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 up = 0, right = n - 1;
while (up < m && right >= 0) {
if (matrix[up][right] == target)
return true;
else if (matrix[up][right] < target)
up++;
else
right--;
}
return false;
}
};