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.
M1: heap,建立一个min heap,先把最小元素{0, 0}放进heap。用cnt计数,如果++cnt == k时,找到第k小的元素,返回。
因为数组每行每列都是有序的,每次循环时把heap中的最小值poll出来,如果是第一行,把该元素右边的元素加入heap,然后把该元素下方的元素加入heap。用一个参数cnt计数,当++cnt = k里,返回matrix对应坐标的值。
time: O(klogk), space: O(k)
class Solution { public int kthSmallest(int[][] matrix, int k) { PriorityQueue<int[]> minHeap = new PriorityQueue<>(k, (a, b) -> matrix[a[0]][a[1]] - matrix[b[0]][b[1]]); int cnt = 0; minHeap.add(new int[] {0, 0}); while(true) { int[] pair = minHeap.poll(); if(++cnt == k) return matrix[pair[0]][pair[1]]; if(pair[0] == 0 && pair[1] + 1 < matrix[0].length) minHeap.add(new int[] {pair[0], pair[1] + 1}); if(pair[0] + 1 < matrix.length) minHeap.add(new int[] {pair[0] + 1, pair[1]}); } } }
另一种写法:
从最小的元素开始,依次访问最小元素的neighbor(当neighbor下标不越界且没被访问过,入队,并标记为已访问),循环k次。最后最小堆的堆顶元素就是第k小元素的坐标
time: O(klogk), space: O(k + n^2)
class Solution { public int kthSmallest(int[][] matrix, int k) { boolean[][] visited = new boolean[matrix.length][matrix[0].length]; PriorityQueue<int[]> minHeap = new PriorityQueue<>((a, b) -> matrix[a[0]][a[1]] - matrix[b[0]][b[1]]); minHeap.offer(new int[] {0, 0}); for(int i = 0; i < k - 1; i++) { int[] idx = minHeap.poll(); int row = idx[0], col = idx[1]; visited[row][col] = true; if(row + 1 < matrix.length && !visited[row+1][col]) { minHeap.offer(new int[] {row + 1, col}); visited[row+1][col] = true; } if(col + 1 < matrix[0].length && !visited[row][col+1]) { minHeap.offer(new int[] {row, col + 1}); visited[row][col+1] = true; } } int[] res = minHeap.peek(); return matrix[res[0]][res[1]]; } }
M2: binary search,原理同 287. find the duplicate number https://www.cnblogs.com/fatttcat/p/9986854.html
time: O(NlogN), space: O(1)