https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix/
给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。
提示:
你可以假设 k 的值永远是有效的,1 ≤ k ≤ n2 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
矩阵的每一行都是一个升序的数组,用合并多个有序数组的思路,找出前 k 个最小的元素就行。
用 n 个指针来记录每一行当前最小元素。
- 时间复杂度:$O(k*n)$,n 是矩阵宽高,其中 k 最坏的情况下是
$n^2$ ,所以最坏的时间复杂度是$O(n^3)$ 。 - 空间复杂度:$O(n)$,指针数组的长度。
JavaScript Code
/**
* @param {number[][]} matrix
* @param {number} k
* @return {number}
*/
var kthSmallest = function (matrix, k) {
const rows = matrix.length;
const cols = matrix[0].length
const indices = Array(rows).fill(0);
let kth;
while (k-- > 0) {
let min = Infinity
let minRow = -1
for (let r = 0; r < rows; r++) {
if (indices[r] >= cols) continue
const num = matrix[r][indices[r]];
if (num <= min) {
min = num;
minRow = r
}
}
kth = min
indices[minRow]++;
}
return kth;
};
还是上一个方法的思路,只不过在寻找多行中的最小值时,不用循环查找,而是用堆将这个查找时间从 n 降到 logn。
- 时间复杂度:$O(klogn)$,n 是矩阵宽高,其中 k 最坏的情况下是 $n^2$,所以最坏的时间复杂度是 $O(n^2logn)$。
- 空间复杂度:$O(n)$,堆的大小。
JavaScript Code
/**
* @param {number[][]} matrix
* @param {number} k
* @return {number}
*/
var kthSmallest = function (matrix, k) {
const list = matrix.map((row, x) => [row[0], x, 0]);
// 堆中的数据结构是 [num, x, y]
const heap = new MinHeap(list, function comparator(inserted, compared) {
return inserted[0] > compared[0];
});
while (k-- > 1) {
const [, x, y] = heap.pop();
if (y < matrix[0].length - 1) {
heap.insert([matrix[x][y + 1], x, y + 1]);
}
}
return heap.pop()[0];
};
// **************************************************
class Heap {
constructor(list = [], comparator) {
this.list = list;
this.comparator = comparator;
this.init();
}
init() {
const size = this.size();
for (let i = Math.floor(size / 2) - 1; i >= 0; i--) {
this.heapify(this.list, size, i);
}
}
insert(n) {
this.list.push(n);
const size = this.size();
for (let i = Math.floor(size / 2) - 1; i >= 0; i--) {
this.heapify(this.list, size, i);
}
}
peek() {
return this.list[0];
}
pop() {
const last = this.list.pop();
if (this.size() === 0) return last;
const returnItem = this.list[0];
this.list[0] = last;
this.heapify(this.list, this.size(), 0);
return returnItem;
}
size() {
return this.list.length;
}
}
class MinHeap extends Heap {
constructor(list, comparator) {
if (typeof comparator != 'function') {
comparator = function comparator(inserted, compared) {
return inserted > compared;
};
}
super(list, comparator);
}
heapify(arr, size, i) {
let smallest = i;
const left = Math.floor(i * 2 + 1);
const right = Math.floor(i * 2 + 2);
if (left < size && this.comparator(arr[smallest], arr[left]))
smallest = left;
if (right < size && this.comparator(arr[smallest], arr[right]))
smallest = right;
if (smallest !== i) {
[arr[smallest], arr[i]] = [arr[i], arr[smallest]];
this.heapify(arr, size, smallest);
}
}
}