import java.util.*; /** * NC357 矩阵第K小 * @author d3y1 */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param matrix int整型ArrayList<ArrayList<>> * @param k int整型 * @return int整型 */ public int KthinMatrix (ArrayList<ArrayList<Integer>> matrix, int k) { // return solution1(matrix, k); // return solution2(matrix, k); return solution3(matrix, k); } /** * 堆 * @param matrix * @param k * @return */ private int solution1(ArrayList<ArrayList<Integer>> matrix, int k){ PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(); int n = matrix.size(); for(int i=0; i<n; i++){ for(int j=0; j<n; j++){ minHeap.offer(matrix.get(i).get(j)); } } while(!minHeap.isEmpty() && --k>0){ minHeap.poll(); } return minHeap.peek(); } /** * 归并 + 小根堆: 利用行有序性 * @param matrix * @param k * @return */ private int solution2(ArrayList<ArrayList<Integer>> matrix, int k){ int n = matrix.size(); // PriorityQueue<int[]> minHeap = new PriorityQueue<>(new Comparator<int[]>(){ // @Override // public int compare(int[] o1, int[] o2){ // return o1[0]-o2[0]; // } // }); // PriorityQueue<int[]> minHeap = new PriorityQueue<>((o1, o2) -> o1[0]-o2[0]); PriorityQueue<int[]> minHeap = new PriorityQueue<>(Comparator.comparingInt(o -> o[0])); int row,col,num; for(int i=0; i<n; i++){ row = i; col = 0; num = matrix.get(row).get(col); minHeap.offer(new int[]{num, row, col}); } while(!minHeap.isEmpty() && --k>0){ int[] curr = minHeap.poll(); if(curr[2] != n-1){ row = curr[1]; col = curr[2]+1; num = matrix.get(row).get(col); minHeap.offer(new int[]{num, row, col}); } } return minHeap.peek()[0]; } /** * 二分: 利用行列有序性 * @param matrix * @param k * @return */ private int solution3(ArrayList<ArrayList<Integer>> matrix, int k){ int n = matrix.size(); // 矩阵最小值 int left = matrix.get(0).get(0); // 矩阵最大值 int right = matrix.get(n-1).get(n-1); int mid; while(left <= right){ mid = left+(right-left)/2; // 若cnt(mid)<k, left=mid+1(left增大); 最终left为第一个满足cnt(left)>=k的数, 即为所求 if(check(matrix, k, n, mid)){ left = mid+1; }else{ right = mid-1; } } return left; } /** * 校验: 小于等于mid的个数(cnt)是否小于k * @param matrix * @param k * @param n * @param mid * @return */ private boolean check(ArrayList<ArrayList<Integer>> matrix, int k, int n, int mid){ // 从左下角开始(matrix[n-1][0]) int row = n-1; int col = 0; int cnt = 0; int curr; while(row>=0 && col<n){ curr = matrix.get(row).get(col); // 统计小于等于mid的个数 if(curr <= mid){ cnt += row+1; col++; }else{ row--; } } return cnt<k; } }