二 维 数 组 中 的 查 找
核心考点:数组相关,特性观察,时间复杂度把握 |
描述:
在一个二维数组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
思路:
这一题首先查找元素,我们首先想到的肯定是遍历数组,一个一个元素查找,这时候咱们的思路就被限制了,一次查找一个,效率极其低下,因此我们还得找一个更好的办法
- 查找的过程,本质是一个排除的过程
根据题目的特性,从左到右依次递增,从上到下依次递增,于是我们定两个点,一个是右上角的点,一个是左下角的点。如图:
所以我们在这里就直接可以用我们要查找的元素和右上角的元素进行比较,当要查找的元素比右上角元素大的时候,我们就可以直接把最上面那一行都舍去,因为从左到右依次递增最右边的数值就是最大的,要查找的元素比最大的元素还大那就肯定不在这一行;当要查找的元素比右上角元素小的时候,就可以直接省去最右边的一列,道理是一样的,然后继续这样比较下去。
- 注意:临界条件
代码实现:
- 先考虑特殊情况,数组为空的时候
if(array == null){
return false;
}
- 定义下标,为了取到右上角元素
int i = 0;
int j = array[0].length - 1;
注意 i 是行,j 是列,其中 array[0].length - 1 是代表第一行的长度减去 1 ,就是第一行最后一个元素的下标,因为下标都是从 0 开始的。
- 用循环来判断并且排除
while( i < array.length && j >= 0){
if(target < array[i][j]){//array[i][j]一定是当前行最大的,当前列最小的
//target < array[i][j] 排除当前列
j--;
}
else if(target > array[i][j]){
//target > array[i][j] 排除当前行
i++;
}
else{
//找到
return true;
}
}
return false;
- while 循环中的条件就是行 i 和列 j 都需要有合法性,i 是行,必须要有元素才可以,无论几行,j 是列,可以是一列及其以上,下标从 0 开始,所以大于等于 0 。
- 当查找的值小于右上角的值的时候,就可以把最右边的一列省去,因为从上往下递增,右上角最小
- 当查找的值大于右上角的值的时候,就可以把最上面的一行省去,因为从左往右递增,右上角最大
附上总的代码
public class Solution {
public boolean Find(int target, int [][] array) {
if(array == null){
return false;
}
int i = 0;
int j = array[0].length - 1;
while( i < array.length && j >= 0){
if(target < array[i][j]){//array[i][j]一定是当前行最大的,当前列最小的
//target < array[i][j] 排除当前列
j--;
}
else if(target > array[i][j]){
//target > array[i][j] 排除当前行
i++;
}
else{
//找到
return true;
}
}
return false;
}
}