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;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章