二维数组的查找
题目描述:
- 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
题目难点:
-
首先暴力算法就不要想了,面试不可能回答出这种想法
-
其实很明显这是一个类似于图的深度搜索的问题,我们如果从nums【0】【0】开始查找,那么就分为三种情况
- 如果target = nums【i】【j】,那么进行输出
- 如果target > nums【i】【j】,则数据可能在nums【i】【j】的右边或者下面
- 如果target < nums【i】【j】,则数据可能在nums【i】【j】的左边或者上面
-
那么我们会发现,无论是第二种情况还是第三种情况,两个不同的方向都会有交叉的地方(也就是右边和上面会交叠,左边和上面会交叠),如图:两个区域会交叠
-
所以这就是一个棘手的问题,由于区域会交叠,那么对于算法的复杂性就提升了,并且也很难判断在哪里!
算法思路:
- 目前来说,我们遇见的问题就在于每次搜索判断之后的两个不同方向的区域会进行交叠,那我们能不能找到一种搜索方式,每次就可以很明确的告诉我们下一次搜索的方向!
- 实际上,如果我们只需要从右上角开始搜索,这样问题就很好的解决了!
- 该算法的核心就是每次只比较右上角的元素,这样就不会出现方向区域的重叠
- 我们以 target = 7为例,从9开始进行搜索,由于7小于9,而9是这一列的最大值,所以7不可能在这一列上,必定在9的左边区域,所以我们就可以将这一列从矩阵中去除掉。
- 之后我们再比较8这个元素,和之前同理,方向还是在左边,可以除去这一列
- 此时我们的矩阵区域只剩下了两列,那么此时比较2元素,因为7大于2,而2又是这一行中最大的元素,所以7不可能在这一行中,那么方向一定是往下的!
- 然后比较4,再往下走,就可以找到元素了
- 总的来说就是每次比较右上角的元素,然后除去矩阵的一定范围,并且每次搜索的方向是很明确的,要不然是在左边,要不然是在上面,这样就很好的解决了区域重叠的问题
具体实现:
public static boolean searchInSecond1(int[][] nums, int target){
//记录比较的位置
int targetRow = 0;
int targetCloum = nums[0].length-1;
while(targetRow < nums.length && targetCloum >= 0){
if(target == nums[targetRow][targetCloum]) return true;
else if( target > nums[targetRow][targetCloum]){
targetRow++;
}else {
targetCloum--;
}
}
return false;
}
总结
- 在二维数组中的查找时,其实类似于图的搜索,我们尽可能的每次搜索时都可以知道下一次搜索的明确方向,那么这种搜索算法一定是最优的!