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.
思路1:klogk, 将最左上角的node加入priorityqueue,然后比这个点大的,只能是下面和右边,然后把这两个点加入,然后每次poll最小的,然后把接下来的点加入;
class Solution {
class Node {
public int x;
public int y;
public int value;
public Node(int x, int y, int value) {
this.x = x;
this.y = y;
this.value = value;
}
}
public int kthSmallest(int[][] matrix, int k) {
int count = 0;
int n = matrix.length;
boolean[][] visited = new boolean[n][n];
PriorityQueue<Node> pq = new PriorityQueue<Node>((a, b) -> (a.value - b.value));
pq.offer(new Node(0, 0, matrix[0][0]));
visited[0][0] = true;
int res = matrix[0][0];
while(!pq.isEmpty() && count < k) {
Node node = pq.poll();
count++;
if(count == k) {
return node.value;
}
if(node.y + 1 < n && !visited[node.x][node.y + 1]) {
pq.offer(new Node(node.x, node.y + 1, matrix[node.x][node.y + 1]));
visited[node.x][node.y + 1] = true;
}
if(node.x + 1 < n && !visited[node.x + 1][node.y]) {
pq.offer(new Node(node.x + 1, node.y, matrix[node.x + 1][node.y]));
visited[node.x + 1][node.y] = true;
}
}
return -1;
}
}
思路2:二维数组中左上角的肯定是最小值,右下角的肯定是最大值,我们取他们的平均值,然后计算小于等于平均值的数字的个数,如果个数是小于k,那么说明要求的值是要大于平均值的,此时我们更新start的值;如果个数是大于k,那么说明要求的值就在start和mid之间,此时更新end的值。
中心思想是用start,end来逼近那个第k大的值,因为是整数,所以一直在用count来逼近,而不是找index坐标。注意count的时候,从左下角开始计算,如果matrix[x][y]比mid大,x上移,如果matrix[x][y]比mid小,count += x+1; O(nlgn)
class Solution {
public int kthSmallest(int[][] matrix, int k) {
if(matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return -1;
}
int n = matrix.length;
int start = matrix[0][0];
int end = matrix[n - 1][n - 1];
while(start + 1 < end) {
int mid = start + (end - start) / 2;
if(count(matrix, mid) < k) {
start = mid;
} else {
// count(matrix, mid) >= k;
end = mid;
}
}
if(count(matrix, start) < k) {
return end;
}
return start;
}
// 算 <= target的个数;
private int count(int[][] matrix, int target) {
int n = matrix.length;
int cnt = 0;
int x = n - 1;
int y = 0;
while(0 <= x && x < n && 0 <= y && y < n) {
if(target >= matrix[x][y]) {
cnt += x + 1; // 注意x, y是index,所以是0 base的,算个数,要+1;
y++;
} else {
// target < matrix[x][y];
x--;
}
}
return cnt;
}
}