240. 搜索二维矩阵 II
思路:矩阵从左到右,从上到下递增,例如:
[
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
]
因为矩阵的右上角是该行最大的元素,也是该列最小的元素,所以我们从右上角出发开始于目标数进行比较,如果大于目标树则往左扫描,若小于目标数则往下扫描,完整代码如下:
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false;
int m = matrix.length, n = matrix[0].length;
int row = 0, col = n - 1;
while (row < m && col >= 0) {
if (target == matrix[row][col]) return true;
else if (target < matrix[row][col]) col--;
else row++;
}
return false;
}
378. 有序矩阵中第K小的元素
思路:矩阵的规律和上面一题一样,由于是求第K小的元素,那么一定可以用堆,也就是大顶堆。首先遍历矩阵,将所有元素加入到优先队列中,如果队列中元素大于k个就让堆顶出堆即可:
public int kthSmallest(int[][] matrix, int k) {
if(matrix.length == 0) return 0;
PriorityQueue<Integer> heap = new PriorityQueue<>((o1,o2)->(o2-o1));
for(int i=0;i<matrix.length;i++){
for(int j=0;j<matrix[0].length;j++){
heap.add(matrix[i][j]);
if(heap.size()>k) heap.poll();
}
}
return heap.peek();
}
但是这种方法没有利用到这个数组的递增规律,所以如何利用这个规律呢?那当然就是使用二分法啦。这因为左上角和右下角是矩阵中最小和最大的元素,我们可以通过二分法不断的确定一个值,矩阵中小于等于该值的元素个数不小于k。完整代码如下:
public int kthSmallest(int[][] matrix, int k) {
int m = matrix.length, n = matrix[0].length;
int lo = matrix[0][0], hi = matrix[m - 1][n - 1];
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
int cnt = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n && matrix[i][j] <= mid; j++) {
cnt++;
}
}
if (cnt < k) lo = mid + 1;
else hi = mid;
}
return lo;
}
那么如何保证最后的lo一定是矩阵中的元素呢?如果mid计算的cnt大于k就会right就会减,等于还会减,如果小于就会加,最后肯定能归为矩阵的值。因为大了right会一直减下去,所以这个值肯定不会比矩阵中的目标值大,但是这个值又不能小,小了cnt就会小于k了,所以只能等于的时候才能成立。
但是,我每次都搞不定二分法,所以我还是乖乖用堆⑧o( ̄▽ ̄)o