给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。
你必须找到一个内存复杂度优于 O(n2) 的解决方案。
示例 1:
输入:matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8
输出:13
解释:矩阵中的元素为 [1,5,9,10,11,12,13,13,15],第 8 小元素是 13
示例 2:
输入:matrix = [[-5]], k = 1
输出:-5
C代码1:排序qsort
int cmp(const void *a, const void *b) {
return *(int*)a - *(int*)b;
}
// 第k大、第k小这种题型、第一时间就应该想到【排序】
int kthSmallest(int** matrix, int matrixSize, int* matrixColSize, int k){
int* arr = (int*)malloc(sizeof(int) * matrixSize * matrixColSize[0]);
int l = 0;
for (int i = 0; i < matrixSize; ++i) {
for (int j = 0; j < matrixColSize[0]; ++j) {
arr[l++] = matrix[i][j];
}
}
qsort(arr, l, sizeof(int), cmp); // l: 数组长度
return arr[k - 1];
}
Java代码1:排序
public int kthSmallest(int[][] matrix, int k) {
int rows = matrix.length;
int cols = matrix[0].length;
int[] arr = new int[rows * cols];
int idx = 0;
for (int[] row : matrix) {
for (int num : row) {
arr[idx++] = num;
}
}
Arrays.sort(arr);
return arr[k - 1];
}
Java代码2:优先级队列(小顶堆)
public int kthSmallest(int[][] matrix, int k) {
PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>() {
public int compare(int[] a, int[] b) {
return a[0] - b[0]; // 小顶堆
}
});
int n = matrix.length;
for (int i = 0; i < n; i++) {
pq.offer(new int[]{matrix[i][0], i, 0}); // 第i行第0列元素,第i行,第0列
}
for (int i = 0; i < k - 1; i++) {
int[] now = pq.poll();
if (now[2] != n - 1) { // now[2] + 1边界
pq.offer(new int[]{matrix[now[1]][now[2] + 1], now[1], now[2] + 1});
}
}
return pq.poll()[0];
}
Java代码3:二分查找、区域中的个数 vs k
left、right、mid
public int kthSmallest(int[][] matrix, int k) {
int n = matrix.length;
int l = matrix[0][0];
int r = matrix[n - 1][n - 1];
while (l < r) { // 以值为二分,不是二分下标
int mid = l + ((r - l) >> 1);
if (check(matrix, mid, k, n)) { // 主要传参: mid
r = mid; // 区域的个数 >= k,即 r就要左移(收缩范围)
} else {
l = mid + 1; // 区域的个数 < k,即 l就要右移(扩大范围:l扩大,使mid扩大)
}
}
return l;
}
public boolean check(int[][] matrix, int mid, int k, int n) {
int i = n - 1;
int j = 0;
int num = 0;
while (i >= 0 && j < n) {
if (matrix[i][j] <= mid) {
num += i + 1; // 【记录小于mid的个数】 当前元素小于mid,则此元素及上方元素均小于mid。
j++;
} else {
i--;
}
}
return num >= k;
}