https://leetcode.com/problems/search-a-2d-matrix/
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
- Integers in each row are sorted from left to right.
- The first integer of each row is greater than the last integer of the previous row.
For example,
Consider the following matrix:
[ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50] ]
Given target = 3
, return true
.
解题思路:
这道题属于常规思路,两次二分查找。首先二分查找应该在的行,然后再在该行内做一次标准的二分查找。
如果matrix[mid][0] > target,说明要找的数比mid行第一个数小,那么一定在mid行以前。如果matrix[mid][0] < target,说明target比mid行第一个数字大,那么有可能就在mid行,也有可能在mid行往后的行。
这时就通过对比mid行最后一个数字和target的大小来判断。
public class Solution { public boolean searchMatrix(int[][] matrix, int target) { int start = 0; int end = matrix.length - 1; int row = -1; while(start <= end){ int mid = (start + end) / 2; if(matrix[mid][0] == target){ return true; } if(matrix[mid][0] > target){ end = mid - 1; } if(matrix[mid][0] < target){ if(matrix[mid][matrix[mid].length - 1] == target){ return true; } if(matrix[mid][matrix[mid].length - 1] > target){ row = mid; break; } if(matrix[mid][matrix[mid].length - 1] < target){ start = mid + 1; } } } if(row == -1){ return false; } start = 0; end = matrix[row].length - 1; while(start <= end){ int mid = (start + end) / 2; if(matrix[row][mid] == target){ return true; } if(matrix[row][mid] < target){ start = mid + 1; } if(matrix[row][mid] > target){ end = mid - 1; } } return false; } }
后来看到网友在第一次二分搜索,即搜索行的时候,有比较简洁,但需要理解一下的方法。就是直接用end作为最后的行。我们看看如何证明?
假设有行4、22、35、47、89、100、120,我们想找90,应该在89那一行。第一次mid=47,于是start到了89那一行。然后mid=100,于是end=89。这时start=end=89。要找90,start++,到了100。循环退出。
可以看到end正好在要找的那一行,而start则超过了一行。
为什么会这样?因为end是当target<mid的时候更新的,如果target存在,最后一次搜索一定是start=end=mid落在target所在行,target只可能>mid,所以只会更新start++。这样最终end一定在target所在的行上,除非end减到最后已经为-1了。
public class Solution { public boolean searchMatrix(int[][] matrix, int target) { int start = 0; int end = matrix.length - 1; int row = -1; while(start <= end){ int mid = (start + end) / 2; if(matrix[mid][0] == target){ return true; } if(matrix[mid][0] > target){ end = mid - 1; } if(matrix[mid][0] < target){ start = mid + 1; } } row = end; if(row == -1){ return false; } start = 0; end = matrix[0].length - 1; while(start <= end){ int mid = (start + end) / 2; if(matrix[row][mid] == target){ return true; } if(matrix[row][mid] < target){ start = mid + 1; } if(matrix[row][mid] > target){ end = mid - 1; } } return false; } }
这道题本身不难,但是对理解二分查找的过程,特别是两端指针更新的条件和结果,循环的过程,还是比较好的。