Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix. Note that it is the kth smallest element in the sorted order, not the kth distinct element. Example: matrix = [ [ 1, 5, 9], [10, 11, 13], [12, 13, 15] ], k = 8, return 13. Note: You may assume k is always valid, 1 ≤ k ≤ n2.
在一个从左到右,从上到下均有序的二维数组中,找到从小到第k个数字,这里须要注意,不要求必定要是惟一的值,即假设存在这样一个序列1,2,2,3
,则第三个数字是2而不是3。java
当涉及到从一个集合中查找一个元素这样的问题时,咱们每每会马上想到查找的几种方式:有序数组查找,无序数组查找,堆排序。这里若是将二维数组转化为一维有序数组,成本未免太大了。同理,将其中全部元素都转化为堆,也会存在内存不足的问题。所以咱们能够采用部分元素堆排序便可。即咱们每次只须要可能构成第k个元素的值进行堆排序就能够了。数组
public int kthSmallest(int[][] matrix, int k) { //优先队列 PriorityQueue<Tuple> queue = new PriorityQueue<Tuple>(); //将每一行的第一个元素放入优先队列中 for(int i = 0 ; i<matrix.length ; i++) { queue.offer(new Tuple(i, 0, matrix[i][0])); } //对优先队列执行k次取操做,取出来的就是第k个值 for(int i = 0 ; i<k-1 ; i++) { Tuple t = queue.poll(); //判断是否到达行尾,若没有,则将下一个元素做为潜在的第k个元素加入优先队列中 if(t.y == matrix[0].length-1) continue; queue.offer(new Tuple(t.x, t.y+1, matrix[t.x][t.y+1])); } return queue.poll().value; } /** * 存储矩阵中x,y和该下标上对应的值的Tuple */ public static class Tuple implements Comparable<Tuple>{ int x; int y; int value; public Tuple(int x, int y, int value) { this.x = x; this.y = y; this.value = value; } @Override public int compareTo(Tuple o) { // TODO Auto-generated method stub return this.value - o.value; } }
二分查找的核心问题在于,如何找到查找的上界和下届。这边咱们能够矩阵中的最大值和最小值做为上界和下界。而后不停的与中间值进行比较,判断当前矩阵中小于该中间值的元素有几个,若是数量不足k,就将左指针右移,不然,就将右指针左移。直到左右指针相遇。这里须要注意,不能在数量等于k的时候就返回mid值,由于mid值不必定在矩阵中存在。ide
public int kthSmallest2(int[][] matrix, int k){ int low = matrix[0][0], high = matrix[matrix.length-1][matrix[0].length-1]; while(low <= high) { int mid = low + (high - low) / 2; int count = 0; int i = matrix.length-1 , j = 0; //自矩阵左下角开始计算比mid小的数字的个数 while(i>=0 && j < matrix.length){ if(matrix[i][j]>mid) i--; else{ count+=i+1; j++; } } if(count < k) { low = mid + 1; }else{ high = mid - 1; } } return low; }