开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第19天,点击查看活动详情
题目
描述
在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[
[1,2,8,9], [2,4,9,12], [4,7,10,13], [6,8,11,15]
]
给定 target = 7,返回 true。
给定 target = 3,返回 false。
数据范围:矩阵的长宽满足 0≤n,m≤500 , 矩阵中的值满足 0≤val≤10^9 进阶:空间复杂度O(1) ,时间复杂度 O(n+m)
示例1
输入:
7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]
返回值:
true
说明:
存在7,返回true
示例2
输入:
1,[[2]]
返回值:
false
示例3
输入:
3,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]
返回值:
false
说明:
不存在3,返回false
分析
分析特殊情况
简单分析可知,当二维数组为空时,不管查找什么target,都只需要返回空。
分析一般情况
顺序遍历方法
最容易想到的便是两层遍历,对每一行中的每一个元素进行遍历,与target进行对比,如果相等则返回true,否则最后返回false,如下:
for(auto line : array)
{
for(auto element : line)
{
if(element == target)
{
return true;
}
}
}
return false;
但是这个方法很明显没有使用二维数组已经排序的信息,所以进行了全局遍历,时间复杂度为O(mn),不符合题意。
路径遍历方法
首先我们观察一下数组中的元素,按行从左到右增大,按列从上到下增大,那么左上角的是最小的元素,右下角的是最大的元素;对于左下角的元素,它总是比它上面的元素大,比它右边的元素小,右上角的元素总是比它下面的元素小,比它左边的元素大。
这样一看,左下角和右下角的元素就有一点像二分查找里面的中点元素了,这里我们考察左下角元素。
- 首先与target进行比较,如果相等,那就返回true;
- 如果比target小,说明下一步我们应该找一个比它大的比较,所以应该查看右边的元素;
- 如果比target大,说明下一步我们应该找一个比它小的比较,所以应该查看上边的元素。
那么直到什么时候我们可以停止查找呢?
- 首先是我们查找的范围不能跳出二维数组的范围,即如果用x,y表示行号和列号,二维数组有m行,n列,那么我们从(m-1,0)出发,最终我们的x小于0停止,y大于n-1也要停止;
- 其次是我们考虑最坏的情况,即,我们要寻找的元素在右上角,那么我们最多要走m+n-2步,不会有更多的步数了。
代码示例
逻辑如上面分析所说
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
size_t line = array.size();
if(line == 0)
{
return false;
}
size_t column = array[0].size();
int x = line -1;
int y = 0;
int n = line + column - 2;
while(y < column && x >= 0 && n >= 0)
{
if(array[x][y] == target)
{
return true;
}
else if(array[x][y] < target)
{
y++;
}
else if(array[x][y] > target)
{
x--;
}
n--;
}
return false;
}
};