leetcode378. Kth Smallest Element in a Sorted Matrix
題目要求
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。
思路一:優先佇列
當涉及到從一個集合中查詢一個元素這樣的問題時,我們往往會立刻想到查詢的幾種方式:有序陣列查詢,無序陣列查詢,堆排序。這裡如果將二維陣列轉化為一維有序陣列,成本未免太大了。同理,將其中所有元素都轉化為堆,也會存在記憶體不足的問題。因此我們可以採用部分元素堆排序即可。即我們每次只需要可能構成第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值不一定在矩陣中存在。
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; }