这个问题是数据结构与算法中的经典题目之一,常用于考察排序、堆、优先队列的应用。以下是几种常见的解法及其时间复杂度分析:
解法一:排序法(适合数据量不大)
思路:
- 直接对数组进行排序
- 取前 K 个元素
cpp
#include <vector>
#include <algorithm>
std::vector<int> topKSort(std::vector<int>& nums, int k) {
std::sort(nums.begin(), nums.end(), std::greater<int>());
return std::vector<int>(nums.begin(), nums.begin() + k);
}
时间复杂度:
- 排序时间复杂度:
O(n log n)
- 空间复杂度:
O(1)
解法二:最小堆(推荐,适合大数据)
思路:
- 使用大小为 K 的最小堆来保存当前最大的 K 个元素
- 遍历整个数组,若当前元素比堆顶大,则替换堆顶
cpp
#include <vector>
#include <queue>
std::vector<int> topKHeap(const std::vector<int>& nums, int k) {
if (k == 0)
return {};
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
for (int num : nums) {
if (minHeap.size() < k) {
minHeap.push(num);
} else if (num > minHeap.top()) {
minHeap.pop();
minHeap.push(num);
}
}
std::vector<int> result;
while (!minHeap.empty()) {
result.push_back(minHeap.top());
minHeap.pop();
}
std::sort(result.rbegin(), result.rend()); // 可选:从大到小排序
return result;
}
时间复杂度:
- 时间复杂度:
O(n log k)
- 构建堆:
O(k)
- 遍历其余 <math xmlns="http://www.w3.org/1998/Math/MathML"> n − k n - k </math>n−k 个元素,每次
O(log k)
:总共O((n-k) log k)
- 构建堆:
- 空间复杂度:
O(k)
🔥 解法三:快排的思想(Top-K 问题,适合不要求完整排序)
思路:
- 类似快速排序中的分区(partition),选定一个"枢轴",将大于 pivot 的放左边,小于的放右边
- 不断递归,直到找到第 K 个最大的数为止
cpp
#include <vector>
#include <cstdlib> // for rand()
int partition(std::vector<int>& nums, int left, int right) {
int pivot = nums[right], i = left;
for (int j = left; j < right; ++j) {
if (nums[j] >= pivot) {
std::swap(nums[i], nums[j]);
++i;
}
}
std::swap(nums[i], nums[right]);
return i;
}
void quickSelect(std::vector<int>& nums, int left, int right, int k) {
if (left >= right)
return;
int pivotIndex = partition(nums, left, right);
if (pivotIndex == k)
return;
else if (pivotIndex < k)
quickSelect(nums, pivotIndex + 1, right, k);
else
quickSelect(nums, left, pivotIndex - 1, k);
}
std::vector<int> topKQuickSelect(std::vector<int>& nums, int k) {
quickSelect(nums, 0, nums.size() - 1, k);
return std::vector<int>(nums.begin(), nums.begin() + k);
}
时间复杂度:
-
平均:
O(n)
- 最坏(退化成链表):
O(n^2)
- 最坏(退化成链表):
-
空间复杂度:
O(1)
(递归栈不计)
✅ 总结对比
方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
---|---|---|---|
排序法 | O(n log n) | O(1) | 数据量小,代码简单 |
最小堆 | O(n log k) | O(k) | 数据量大,k 远小于 n |
快速选择 | 平均 O(n) | O(1) | 不关心顺序,只要前 K 大 |