1. 题目来源
链接:二维数组中的查找
来源:LeetCode——《剑指-Offer》专项
2. 题目说明
在一个 n * m
的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例 :
[
[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
3. 题目解析
3.1 方法一:暴搜
这是个没有营养的解答,会浪费你 10 秒钟~~~
// 执行用时 :28 ms, 在所有 C++ 提交中击败了96.72%的用户
// 内存消耗 :12.2 MB, 在所有 C++ 提交中击败了100.00%的用户
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
if (matrix.empty() || matrix[0].empty())
return false;
for (int i = 0; i < matrix.size(); ++i) {
for (int j = 0; j < matrix[0].size(); ++j) {
if (matrix[i][j] == target)
return true;
}
}
return false;
}
};
3.2 方法二:数学规律法
仔细观察题目中给的那个例子,如果从左上角开始搜索,它的右方与下方都是增长方向,从右下角开始搜索,它的上方与左方都是增长方向,无法进行判断。故搜索不能从这两个标志数开始,需要找到一方增长、一方减小的路径,满足 if
else
结构才能够完成。
可以发现有两个位置的数字很有特点,左下角和右上角的数。左下角的18,往上所有的数变小,往右所有数增加,那么就可以和目标数相比较:
- 如果目标数大,就往右搜
- 如果目标数小,就往上搜
这样就可以判断目标数是否存在。当然也可以把起始数放在右上角,往左和下搜,停止条件设置正确就行。
如果数组为空、目标数小于 matrix[0][0]
大于 matrix.back().back()
直接返回 false
即可。时间复杂度:
O
(
m
+
n
)
O(m + n)
O(m+n)
参见代码如下:
// 执行用时 :52 ms, 在所有 C++ 提交中击败了18.44%的用户
// 内存消耗 :12.2 MB, 在所有 C++ 提交中击败了100.00%的用户
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
if (matrix.empty() || matrix[0].empty())
return false;
if (target < matrix[0][0] || target > matrix.back().back())
return false;
int x = matrix.size() - 1, y = 0;
while (true) {
if (matrix[x][y] > target)
--x;
else if (matrix[x][y] < target)
++y;
else
return true;
if (x < 0 || y >= matrix[0].size())
break;
}
return false;
}
};