Thinking process I -- Heap

Given a sorted matrix, how to find the kth smallest?

  • the matrix is special, each row and column is sorted in ascending order
  • which means, if x must be smaller than the one on its right and the one on its left

how to get the min/max from finite number of integers.

  • heap
    • add O(log n)
    • poll O(1)

Mistakes

encapsulation

  • class Cell
  • not private or public class Cell

index

  • count < k - 1
  • not cont < k

Time Complexity

O (k log k)

API Method

Comparator interface
class className implements Comparator<Type> {
    public int compare (Type a, Type b) {
        //ascending order
        return a.val - b.val;

        //descending order
        if (a.val < b.val) {
            return 1;
        } else if (a.val > b.val) {
            return -1;
        } else {
            return 0;
        }
    }
}
PriorityQueue init with custom comparator

https://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html

PriorityQueue<Cell> pq = new PriorityQueue<Cell>(1, new CellComparator());

>>>>>>>>Code

class Cell {
    public int x;
    public int y;
    public int val;

    public Cell (int x, int y, int val) {
        this.x = x;
        this.y = y;
        this.val = val;
    }
}

class CellComparator implements Comparator<Cell> {
    public int compare(Cell a, Cell b) {
        return a.val - b.val;
    }
}

public class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        //validate input and check corner cases
        if (matrix.length == 0 || matrix[0].length == 0) return 0;

        int n = matrix.length;
        int m = matrix[0].length;

        PriorityQueue<Cell> pq = new PriorityQueue<Cell>(1, new CellComparator());//min heap
        pq.add(new Cell(0, 0, matrix[0][0]));

        boolean[][] visited = new boolean[n][m];
        visited[0][0] = true;

        int count = 0;

        while (!pq.isEmpty() && count < k - 1) {
            Cell c = pq.poll();

            if (c.x + 1 < n && !visited[c.x + 1][c.y]) {
                pq.add(new Cell(c.x + 1, c.y, matrix[c.x + 1][c.y]));
                visited[c.x + 1][c.y] = true;
            }
            if (c.y + 1 < m && !visited[c.x][c.y + 1]) {
                pq.add(new Cell(c.x, c.y + 1, matrix[c.x][c.y + 1]));
                visited[c.x][c.y + 1] = true;
            }

            count++;
        }

        return pq.poll().val;
    }
}

https://discuss.leetcode.com/topic/52948/share-my-thoughts-and-clean-java-code

The post above mentioned that The key point for any binary search is to figure out the "Search Space". 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".

  • Search by range

Mistakes

How to make sure that this number is actually in the matrix?

  • In helper function, count the numbers that are less or equal to num
  • Because, in this case, comparing with k, the current one should be the one that is kth

In the helper function, how to count the numbers that are less or equal to num?

  • using for loop is not flexible, instead using while loop.

Out of the loop, what to return?

  • Instead of checking the count(left) <= k, it should be larger or equals to k
  • Because, what if there are duplicates?
  • Thinking about this case, [[1,2], [1,3]] find the first

Time Complexity

O (n x n log n)

public class Solution {

    private int count(int num, int[][] matrix) {
        //count all numbers that is less than or equal to num

        int n = matrix.length;
        int m = matrix[0].length;
        int total = m * n;

        int i = n - 1;
        int j = 0;

        while (i >= 0 && j < m) {
            if (matrix[i][j] > num) {
                total -= (m - j);
                i--;
            } else {
                j++;
            }
        }

        return total;
    }

    public int kthSmallest(int[][] matrix, int k) {
        if (matrix.length == 0 || matrix[0].length == 0) return 0;

        int n = matrix.length;
        int m = matrix[0].length;
        int l = matrix[0][0];
        int r = matrix[n - 1][m - 1];

        while (l + 1 < r) {
            int mid = l + (r - l) / 2;
            System.out.println(mid);

            if (count(mid, matrix) < k) {
                l = mid;
            } else {
                r = mid;
            }
        }

        if (count(l, matrix) >= k) {
            return l;
        }

        return r;
    }
}

results matching ""

    No results matching ""