题目描述
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
输入描述
array: 待查找的二维数组 target:查找的数字
输出描述
查找到返回true,查找不到返回false
package com.xxx;
/**
* create by ziqiiii
*/
public class Test {
public static void main(String[] args){
int target =4;
int [][]array={{1,2,8,9},{2,4,9,12},{4,7,10,13},{6,8,11,15}};
System.out.println(Find(target,array));
}
static public boolean Find(int target, int [][] array) {
int row = array.length;
if(row == 0){
return false;
}
int col = array[0].length;
if(col == 0){
return false;
}
//方法一:暴力穷举法 时间复杂度:O(n^2)
// for(int i=0;i<row;i++){
// for(int j=0;j<col;j++){
// if(array[i][j]==target){
// return true;
// }
// }
// }
// return false;
//方法二:找规律:
// 右上角A:左边的值都比A小,下面的值都比A大
// 左下角B:上面的值都比B小,右边的值都比B大
// 所以可以一次性剔除一行或一列
// 不能选左上角(右、下,都比它大),难以判断走向
// 也不能选右下角(左、上,都比它小)
//
//这里选择右上角开始: 时间复杂度:O(n)
int aimI=0, aimJ=col-1;
while(aimI<row && aimJ>=0){
int aim=array[aimI][aimJ];
if(aim == target){
return true;
}else if(aim > target){
aimJ--;
}else {
aimI++;
}
}
return false;
}
}
法二:思路:
思路
从数组中选取数字,和目标数字的关系有三种情况:=,<或>。
-
如果是等于则查找成功;
-
如果是数组中元素小于要查找的数字,说明要查找的数字应该在当前位置的右边或下边。
-
如果是数组中元素大于要查找的数字,说明要查找的数字应该在当前位置的左边或上边。
即 对于数组中的任何一个元素, 比它小的元素都在它的左方或者上方, 比它大的元素都在它的右边或者下方
但是这两个区域还有可能有重叠,比如右边或下边会在右下角有重叠。
为了不重复的处理重叠的数据, 我们可以找几个特殊的起点, 比如
起点 | 性质 | 可否作为起点 |
---|---|---|
左上角 | 没有上方元素(小)和左方元素(小) 只有下方元素(大)和右方元素(大) | 否 |
右上角 | 没有上方元素(小), 和右方元素(大) 只有下方元素(大)和左方元素(小) | 是 |
左下角 | 没有下方元素(大), 和左方元素(小) 只有上方元素(小)和右方元素(大) | 是 |
右下角 | 没有下方元素(大), 和右方元素(大) 只有上方元素(小)和左方元素(小) | 否 |
因此重叠问题的解决方法:
-
如果查找从右上角开始,如果要查找的数字不在右上角,则每次可以剔除一列或一行。
-
也可以从左下角开始
-
但是不能从左上角或者右下角开始。
因为如果选择右上角的元素,
如图,即是我们在二维数组中查找7的轨迹
法三: 一行一行使用二分查找。
该方法没有方法二快,时间复杂度:O(nlogn)
实现:略
牛客网运行结果: