返回
征服算法难题:快速找到数组中最小的 K 个数
前端
2023-04-04 09:39:35
征服算法难题:寻找数组中最小的 K 个数
踏上编程的冒险之旅,一起征服算法难题吧!今天,我们的目标是找出数组中最小的 K 个数,在这个过程中,我们将深入了解排序和堆数据结构。
排序还是堆?理解基本思路
解决这个问题有两条基本路径:
-
排序: 对数组进行排序,然后取前 K 个数。这是一种简单粗暴的方法,但时间复杂度较高。
-
堆: 使用堆数据结构来存储数组中的元素,堆顶元素就是当前最小的数。不断从堆中取出元素,直到取出 K 个数。这种方法的时间复杂度更低。
深入算法细节
排序法: 使用快速排序或归并排序等算法对数组进行排序,然后取出前 K 个数。
堆法:
- 创建最大堆: 最大堆的特点是堆顶元素是堆中最大的元素。
- 插入元素: 将数组中的元素依次插入堆中。
- 弹出元素: 从堆中弹出 K 个元素,即为数组中最小的 K 个数。
代码实现
// 使用堆来找到数组中最小的 k 个数
// 创建一个最大堆
const maxHeap = [];
// 将数组中的元素依次插入堆中
for (let i = 0; i < nums.length; i++) {
insertIntoMaxHeap(maxHeap, nums[i]);
}
// 从堆中弹出 k 个元素
const smallestK = [];
for (let i = 0; i < k; i++) {
smallestK.push(popFromMaxHeap(maxHeap));
}
// 返回最小的 k 个数
return smallestK;
// 插入元素到最大堆中
function insertIntoMaxHeap(heap, element) {
// 将元素添加到堆的末尾
heap.push(element);
// 将堆调整为最大堆
heapifyUp(heap, heap.length - 1);
}
// 从最大堆中弹出元素
function popFromMaxHeap(heap) {
// 将堆顶元素与最后一个元素交换
const temp = heap[0];
heap[0] = heap[heap.length - 1];
heap[heap.length - 1] = temp;
// 将堆调整为最大堆
heapifyDown(heap, 0);
// 弹出最后一个元素
return heap.pop();
}
// 将堆调整为最大堆(自上而下)
function heapifyDown(heap, index) {
// 获取左子节点和右子节点的索引
const leftChildIndex = 2 * index + 1;
const rightChildIndex = 2 * index + 2;
// 获取最大元素的索引
let largestIndex = index;
if (leftChildIndex < heap.length && heap[leftChildIndex] > heap[largestIndex]) {
largestIndex = leftChildIndex;
}
if (rightChildIndex < heap.length && heap[rightChildIndex] > heap[largestIndex]) {
largestIndex = rightChildIndex;
}
// 如果最大元素的索引不等于当前索引,则交换元素并继续调整
if (largestIndex !== index) {
const temp = heap[index];
heap[index] = heap[largestIndex];
heap[largestIndex] = temp;
heapifyDown(heap, largestIndex);
}
}
// 将堆调整为最大堆(自下而上)
function heapifyUp(heap, index) {
// 获取父节点的索引
const parentIndex = Math.floor((index - 1) / 2);
// 如果父节点的元素小于当前元素,则交换元素并继续调整
if (parentIndex >= 0 && heap[parentIndex] < heap[index]) {
const temp = heap[index];
heap[index] = heap[parentIndex];
heap[parentIndex] = temp;
heapifyUp(heap, parentIndex);
}
}
复杂度分析
-
排序法: 时间复杂度为 O(n log n),其中 n 为数组的长度。
-
堆法: 时间复杂度为 O(n log k),其中 n 为数组的长度,k 为要找的最小的 k 个数。
结语
征服算法难题并非易事,但只要掌握正确的方法和思路,就能够迎难而上,不断提升自己的编程技能。今天分享的两种方法,希望能够助你一臂之力,让你在算法的世界里更上一层楼。
常见问题解答
-
哪种方法更好?
堆法在时间复杂度上更有优势,尤其是当 k 值较小的时候。 -
如何选择 k 值?
k 值的选择取决于具体的应用场景和需求。 -
如何扩展算法来寻找最大的 k 个数?
只需将最大堆替换为最小堆即可。 -
算法还能应用于其他场景吗?
是的,算法还可以应用于其他场景,如查找中位数、第 k 大元素等。 -
如何优化算法的性能?
可以使用各种优化技术,如空间换时间(预先存储已排序数组)、索引跳跃等。