Monday, March 27, 2017

378. Kth Smallest Element in a Sorted Matrix Add to List


The only clear explanation I can find from the web
四刷 08/2022
Version #1 Min Heap
Time O(KlogK) 这里只有logK因为每次只加1to2 new nodes
Space O(K)
Runtime: 24 ms, faster than 47.59% of Java online submissions for Kth Smallest Element in a Sorted Matrix.
Memory Usage: 46.6 MB, less than 99.18% of Java online submissions for Kth Smallest Element in a Sorted Matrix.
class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        int rows = matrix.length;
        int cols = matrix[0].length;
        Queue<int[]> minHeap = new PriorityQueue<>((a, b) -> Integer.compare(matrix[a[0]][a[1]], matrix[b[0]][b[1]]));
        minHeap.offer(new int[]{0, 0});
        int[] curr = new int[2];
        while (k-- > 0) {
            curr = minHeap.poll();
            if (curr[0] == 0 && curr[1] < cols - 1) {
                minHeap.offer(new int[]{curr[0], curr[1] + 1});
            }
            if (curr[0] + 1 < rows) {
                minHeap.offer(new int[]{curr[0] + 1, curr[1]});
            }
        }
        return matrix[curr[0]][curr[1]];
    }
}




三刷 06/2022
Version #1 Min Heap

注意这里不是无脑加每个点的(x+1, y) 和(x, y+1)因为会有重复
应该是只有遇到第一个row的之后才向右展开

Time O(KlogK)
Space O(K)
Runtime: 31 ms, faster than 25.29% of Java online submissions for Kth Smallest Element in a Sorted Matrix.
Memory Usage: 57.1 MB, less than 34.39% of Java online submissions for Kth Smallest Element in a Sorted Matrix.
class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
            throw new IllegalArgumentException("the matrix cannot be empty");
        }
        int rows = matrix.length;
        int cols = matrix[0].length;
        // int[] - x, y
        Queue<int[]> minHeap = new PriorityQueue<>((a, b) -> Integer.compare(matrix[a[1]][a[0]], matrix[b[1]][b[0]]));
        minHeap.offer(new int[]{0, 0});
        int cnt = 0;
        while (!minHeap.isEmpty()) {
            cnt++;
            int[] curr = minHeap.poll();
            int y = curr[1];
            int x = curr[0];
            if (cnt == k) {
                return matrix[y][x];
            }
            if (y + 1 < rows) {
                minHeap.offer(new int[]{x, y + 1});
            }
            // Only expand to the right when it's the first row
            if (y == 0 && x + 1 < cols) {
                minHeap.offer(new int[]{x + 1, y});
            }
        }
        throw new RuntimeException("the total elements in the matric is less than k");
    }
}

Version #2 Binary Search
有一个很关键的点是如何保证binary seach出来的数字一定在matrix里面
Since we are looking for the smallest number from min to max that has k numbers less than or equals to itself

For example  1,  3,  5,  7 -- k = 2

Then any number int [3, 5) will satisfy the criteria, but the smallest number must be 3, which is in the matrix

第二个关键的问题是count smaller or equals to 的时候,是从左下角x = 0, y = rows - 1开始的
Time O(Nlog(max - min))
Space O(1)

class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        //  Find the first number that k elements less than or equals to itself
        if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
            throw new IllegalArgumentException("the matrix cannot be empty");
        }
        int start = matrix[0][0], end = matrix[matrix.length - 1][matrix[0].length - 1];
        while (start < end) {
            int mid = start + (end - start) / 2;
            int count = countSmallerOrEqual(matrix, mid);
            if (count < k) {
                start = mid + 1;
            } else { // count >= k, end = mid
                end = mid;
            }
        }
        return start;
    }
    private int countSmallerOrEqual(int[][] matrix, int num) {
        int y = matrix.length - 1;
        int x = 0;
        int cnt = 0;
        while (x < matrix[0].length && y >= 0) {
            if (matrix[y][x] > num) {
                y--;
            } else {
                cnt += y + 1;
                x++;
            }
        }
        return cnt;
    }
}

一刷
Version #1min heap with extra visited array
Time: O(klogk)
Space:  O(k) for heap O(mn) for the visited array
12.87%
class Cell {
    public int x, y;
    public int val;
    public Cell(int x, int y, int val) {
        this.x = x;
        this.y = y;
        this.val = val;
    }
}
public class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) throw new IllegalArgumentException();
        int count = 0;
        int rows = matrix.length;
        int cols = matrix[0].length;
        Set<Integer> visited = new HashSet<>();
     
        PriorityQueue<Cell> que = new PriorityQueue<>(k, new Comparator<Cell>() {
            public int compare(Cell c1, Cell c2) {
                if (c1.val == c2.val) return 0;
                return c1.val < c2.val ? -1 : 1;
            }
        });
        que.add(new Cell(0, 0, matrix[0][0]));
        visited.add(0 * cols + 0);
        while (!que.isEmpty()) {
            Cell curr = que.poll();
            count++;
            if (count == k) return curr.val;
         
            int x = curr.x;
            int y = curr.y;
         
            if (x + 1 < rows && !visited.contains((x + 1) * cols + y)) {
                que.add(new Cell(x + 1, y, matrix[x + 1][y]));
                visited.add((x + 1) * cols + y);
            }
            if (y + 1 < cols && !visited.contains(x * cols + y + 1)) {
                que.add(new Cell(x, y + 1, matrix[x][y + 1]));
                visited.add(x * cols + y + 1);
            }
        }
        return -1;
    }
}

Version #2 min heap without visited array (polished)
一刷TODO 二刷写的这个Version
感觉已经很漂亮了
二分法的方法做的不是特别透彻
39.97 % 
class Cell {
    public int x, y;
    public int val;
    public Cell(int x, int y, int val) {
        this.x = x;
        this.y = y;
        this.val = val;
    }
}
public class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0 || k <= 0) throw new IllegalArgumentException();
        int rows = matrix.length;
        int cols = matrix[0].length;
        Queue<Cell> minHeap = new PriorityQueue<>(k, new Comparator<Cell>(){
            @Override
            public int compare(Cell c1, Cell c2) {
                return c1.val - c2.val;
            }
        });
        minHeap.offer(new Cell(0, 0, matrix[0][0]));
        Cell curr;
        for (int i = 1; i < k; i++) {
            curr = minHeap.poll();
            if (curr.x == 0 && curr.y + 1 < cols) {
                minHeap.offer(new Cell(curr.x, curr.y + 1, matrix[curr.x][curr.y + 1]));
            }
            if (curr.x + 1 < rows) minHeap.offer(new Cell(curr.x + 1, curr.y, matrix[curr.x + 1][curr.y]));
        }
        return minHeap.peek().val;
    }
}



Version #3 Binary Search
Time: O()
73.44%

public class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) throw new IllegalArgumentException();
        int low = matrix[0][0], high = matrix[matrix.length - 1][matrix[0].length - 1];
        int mid, count;
        while (low < high) {
            mid = low + (high - low) / 2;
            count = search(matrix, mid);
            //TODO
            if (count < k) {
                low = mid + 1;
            } else {
                high = mid;
            }
            //System.out.println("count" + count + "low:" + low + " high:" + high);
        }
        return low;
    }
    //numbers smaller or equal to target
    private int search(int[][] matrix, int target) {
        int i = matrix.length - 1, j = 0;
        int count = 0;
        while (i >= 0 && j < matrix[0].length) {
            if (matrix[i][j] <= target) {
                count = count + i + 1;
                j++;
            } else {
                i--;
            }
        }
        return count;
    }
}

No comments:

Post a Comment