Share my thoughts and Clean Java Code


  • 247

    Solution 1 : Heap
    Here is the step of my solution:

    1. Build a minHeap of elements from the first row.
    2. Do the following operations k-1 times :
      Every time when you poll out the root(Top Element in Heap), you need to know the row number and column number of that element(so we can create a tuple class here), replace that root with the next element from the same column.

    After you finish this problem, thinks more :

    1. For this question, you can also build a min Heap from the first column, and do the similar operations as above.(Replace the root with the next element from the same row)
    2. What is more, this problem is exact the same with Leetcode373 Find K Pairs with Smallest Sums, I use the same code which beats 96.42%, after you solve this problem, you can check with this link:
      https://discuss.leetcode.com/topic/52953/share-my-solution-which-beat-96-42
    public class Solution {
        public int kthSmallest(int[][] matrix, int k) {
            int n = matrix.length;
            PriorityQueue<Tuple> pq = new PriorityQueue<Tuple>();
            for(int j = 0; j <= n-1; j++) pq.offer(new Tuple(0, j, matrix[0][j]));
            for(int i = 0; i < k-1; i++) {
                Tuple t = pq.poll();
                if(t.x == n-1) continue;
                pq.offer(new Tuple(t.x+1, t.y, matrix[t.x+1][t.y]));
            }
            return pq.poll().val;
        }
    }
    
    class Tuple implements Comparable<Tuple> {
        int x, y, val;
        public Tuple (int x, int y, int val) {
            this.x = x;
            this.y = y;
            this.val = val;
        }
        
        @Override
        public int compareTo (Tuple that) {
            return this.val - that.val;
        }
    }
    

    Solution 2 : Binary Search
    We are done here, but let's think about this problem in another way:
    The key point for any binary search is to figure out the "Search Space". For me, I think there are two kind of "Search Space" -- index and range(the range from the smallest number to the biggest number). Most usually, when the array is sorted in one direction, we can use index as "search space", when the array is unsorted and we are going to find a specific number, we can use "range".

    Let me give you two examples of these two "search space"

    1. index -- A bunch of examples -- https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/ ( the array is sorted)
    2. range -- https://leetcode.com/problems/find-the-duplicate-number/ (Unsorted Array)

    The reason why we did not use index as "search space" for this problem is the matrix is sorted in two directions, we can not find a linear way to map the number and its index.

    public class Solution {
        public int kthSmallest(int[][] matrix, int k) {
            int lo = matrix[0][0], hi = matrix[matrix.length - 1][matrix[0].length - 1] + 1;//[lo, hi)
            while(lo < hi) {
                int mid = lo + (hi - lo) / 2;
                int count = 0,  j = matrix[0].length - 1;
                for(int i = 0; i < matrix.length; i++) {
                    while(j >= 0 && matrix[i][j] > mid) j--;
                    count += (j + 1);
                }
                if(count < k) lo = mid + 1;
                else hi = mid;
            }
            return lo;
        }
    }
    

  • 15
    E

    Nice trick, but I think the condition of the first for loop could be changed to

    int bound = matrix.length < k ? matrix.length : k;
    for(int j = 0; j < bound; j++)  {
        pq.offer(new Tuple(0, j, matrix[0][j]));
    }
    

  • 0

    @eprym Smart~


  • 17

    so niubility!!!


  • 0
    A
    This post is deleted!

  • 1
    L

    The runtime would be n + k log(n), no? The first loop is obviously run just n times, and the final loop is k times the the heap operation, which in worst case is 2 * log (n^2) or just log(n).


  • 11
    R

    I think it is also similar to 23. Merge k Sorted Lists


  • 0

    easy to understand!


  • -1
    This post is deleted!

  • -3
    S

    If I am running the algorithm above correctly, then example 1 and example 2 returns 1 and 4. It should return 0 and 1.

    Example 1: matrix = [ [1,2,3], [4,5,6], [0,7,6] ] and k = 1
    Example 2: matrix = [ [3,4,5,6], [2,4,6,8], [6,7,8,9],[0,1,2,3 ] and k = 2


  • 0

    @some_name Did you read the problen carefully ?


  • 0
    S

    @YUANGAO1023
    I thought I did and had originally understood that the values in a row were increasing and the values for a column were increasing.

    One of leetcode's input is [ [1,2], [1,3] ]. In this case matrix[0][0] is not greater than matrix[1][0].

    So, I solved for finding the kth smallest element in a matrix w/ rows and columns elements in a row are ascending.


  • 1

    @some_name
    In your example1, the first column of your input is (1, 4, 0), which is not in ascending order, same as your example 2
    [1,2,3]
    [4,5,6]
    [0,7,6]


  • 0
    S

    @YUANGAO1023 correct. I had read the problem correctly originally, but then misunderstood the problem and was thrown off by a failing solution.


  • 2
    C

    Nice Algorithm. Is the time complexity O(k * logk)? I assume the PriorityQueue does "binary search + insert" to enqueue a new element, so the complexity is logK...


  • 1
    O

    Nice solution, changed a little bit based on yours

    public int kthSmallest(int[][] matrix, int k) {
            int row = matrix.length;
            int col = row == 0 ? 0 : row;
            PriorityQueue<int[]> pq = new PriorityQueue<int[]>(row, new Comparator<int[]>(){
                @Override
                public int compare(int[] arr1, int[] arr2){
                    return matrix[arr1[0]][arr1[1]] - matrix[arr2[0]][arr2[1]];
                }
            });
            
            for(int i = 0; i < col; i++){
                int[] cur = {0, i};
                pq.offer(cur);
            }
            
            for(int i = 0; i < k - 1; i++){
                int[] cur = pq.poll();
                if(cur[0] == row - 1){
                    continue;
                }
                pq.offer(new int[]{cur[0] + 1, cur[1]});
            }
            
            int[] cur = pq.poll();
            return matrix[cur[0]][cur[1]];
        }
    

  • 1
    G

    @olivia_3 This is a good one.

    However, I tried the same code in C++ and got TLE in test case:

    "Last executed input: [[-4646759,-4201117,-3970467,-3952785,-3751128,-3334084,-3241453,-2992243,-2514542,-2213147,-2120566,-1822732,-1468790,-1316752,-1083219,-601869,-541900,-531605,-430222,-285809,-21823,310704,784851,1076583,1173738,1180273,1321993,1740173,1856834,2265269,2752074,3041309,3365300,3682292,3813941,4148468,4467462,4535229,4840063,5336197,5766636,5927253,5937871,6298035,6557411,6927072,7165072,7169132,7407754,7598894,7752482,8035553,8188071,8209235,8679066,9037170,9210746,9284040,9714623,10002322,10081607,10219592,10584533,10732230,10813973,10848004,11024237,11439120,11476855,11806016,12234449,12595534,12720175,13026305,13313763,13514397,13828274,14098655,14585272,14901013,15185937,15259077,15465124,15610197,15753933,15955075,16070315,16341371,16522496,16649218,17007650,17178901,17578021,18044553,18463130,18503981,18993674,19345175,19706118,20033862],[...], ... ]
    9521 "

    Sorry for long post. but really wonder if the limit for C++ was set to bit demanding. I used priority_queue in the same way. No different at all. I can post if anyone interested into a try. Thanks!


  • 4
    R

    c++ version

    class comp{
    public:
        bool operator()(tuple<int, int, int>&a, tuple<int, int, int> &b){
            return get<0>(a) > get<0>(b);
        }
    };
    
    class Solution {
    public:
        int kthSmallest(vector<vector<int>>& matrix, int k) {
            priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, comp> minHeap; //val, row, col
            for(int i = 0;i<matrix[0].size();i++){
                minHeap.push(make_tuple(matrix[0][i], 0, i));
            }
            tuple<int, int, int> result;
            for(int i = 0;i<k;i++){
                result = minHeap.top();
                minHeap.pop();
                if(get<1>(result) == matrix.size()-1)
                    continue;
                int nextRow = get<1>(result) + 1;
                int nextCol = get<2>(result);
                minHeap.push(make_tuple(matrix[nextRow][nextCol], nextRow, nextCol));
            }
            
            return get<0>(result);
        }
    };
    

  • 0
    C

    @chenw2000 the time complexity is logK? why?


  • 0
    C

    @coldWind Just for discussion... I assume that when the priorityQueue do offer(), it will first do binary search for the location to insert, this step is logK.... for the whole algorithm, it will repeat K times, so the overall time complexity is O(KlogK).


Log in to reply
 

Looks like your connection to LeetCode Discuss was lost, please wait while we try to reconnect.