leetcode378. Kth Smallest Element in a Sorted Matrix

Keywords: Java less

Subject requirements

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.

In a two-dimensional array ordered from left to right, from top to bottom, find the number from small to k. It is important to note that there is no need to be a unique value, that is, if there is such a sequence of 1,2,2,3, then the third number is 2 instead of 3.

Idea 1: Priority queue

When it comes to finding an element from a set, we often think of several ways to find it immediately: ordered array search, disordered array search, heap sort. The cost of converting a two-dimensional array into a one-dimensional ordered array is too high. Similarly, if all the elements are converted into heaps, there will be insufficient memory. So we can use partial element heap sort. That is, we only need to sort the heap with the values that may constitute the k element each time.

    public int kthSmallest(int[][] matrix, int k) {
        //Priority queue
        PriorityQueue<Tuple> queue = new PriorityQueue<Tuple>();
        //Put the first element of each row in the priority queue
        for(int i = 0 ; i<matrix.length ; i++) {
            queue.offer(new Tuple(i, 0, matrix[i][0]));
        }
        
        //Perform k fetches on the priority queue, and the k value is taken out.
        for(int i = 0 ; i<k-1 ; i++) {
            Tuple t = queue.poll();
            //Determine whether the end of the line is reached, and if not, add the next element to the priority queue as the potential k-th element
            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;
    }
    
    /**
    * Tuple of the corresponding values of x, y and subscripts in the storage matrix
    */
    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;
        }
    }

Idea 2: Dichotomy Search

The core problem of binary search is how to find the upper bound and the next one. Here we can use the maximum and minimum values of the matrix as upper and lower bounds. Then compare with the intermediate value continuously, judge that there are several elements less than the intermediate value in the current matrix. If the number is less than k, move the left pointer to the right, otherwise, move the right pointer to the left. Until the left and right pointers meet. It should be noted here that mid values cannot be returned when the number equals k, because mid values do not necessarily exist in the matrix.

    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;
            //Starting from the lower left corner of the matrix, the number of digits smaller than mid is calculated
            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;
    }

Posted by johnsonzhang on Thu, 14 Feb 2019 13:24:18 -0800