关于优化的思想,可以参见原文链接
总的来说,方法和时间复杂度如下:
全局排序,O(n*lg(n))
局部排序,只排序TopK个数,O(n*k)
堆,TopK个数也不排序了,O(n*lg(k))
分治法,每个分支“都要”递归,例如:快速排序,O(n*lg(n))
减治法,“只要”递归一个分支,例如:二分查找O(lg(n)),随机选择O(n)
TopK的另一个解法:随机选择+partition
另外再补充下代码部分
1.大小顶堆做法,不用priority_queue
#include <iostream>
#include <assert.h>
#include<vector>
#include<queue>
using namespace std;
class xiaodingdui {
private:
void MoveDown(vector<int>& arr, int moveIndx, int arrLen) {
int leafL = moveIndx * 2 + 1;
int leafR = moveIndx * 2 + 2;
int minIndx = moveIndx;
if (leafL < arrLen) {
minIndx = arr[leafL] < arr[moveIndx] ? leafL : moveIndx;
}
if (leafR < arrLen) {
minIndx = arr[leafR] < arr[minIndx] ? leafR : minIndx;
}
if (minIndx != moveIndx) {
swap(arr[moveIndx], arr[minIndx]);
MoveDown(arr, minIndx, arrLen);
}
return;
}
void BuildHeap(vector<int>& arr) {
for (int i = (arr.size() - 1) / 2; i >= 0; i--) {
MoveDown(arr, i, arr.size());
}
return;
}
public:
vector<int> smallestK(vector<int>& arr, int k) {
vector<int> ret;
BuildHeap(arr);
for (int i = 0; i < k; i++) {
ret.push_back(arr[0]);
swap(arr[0], arr[arr.size() - i - 1]);
MoveDown(arr, 0, arr.size() - i - 1);
}
return ret;
}
};
2.同样是大顶堆排序,priority_queue的实现,会用到额外的空间和数据拷贝,好处是省去了建堆的操作
//同样是大顶堆排序,priority_queue的实现,会用到额外的空间和数据拷贝,好处是省去了建堆的操作
class priority_queue_heap {
public:
vector<int> smallestK(vector<int>& arr, int k) {
vector<int> res;
priority_queue<int> q;
for (int a : arr) {
q.push(a);
if (q.size() > k)
q.pop();
}
while (!q.empty()) {
res.push_back(q.top());
q.pop();
}
return res;
}
};
3.//快排思想,减治法(注意,非分治)
class kuaipai {
public:
vector<int> smallestK(vector<int>& arr, int k) {
if (arr.size() == 0)return vector<int>{};
int n = arr.size();
if (n <= k)return arr;
int left = 0;
int right = arr.size() - 1;
while (left <= right) {
int mid = quicksort(arr, left, right);
if (mid + 1 == k) {
vector<int>result(arr.begin(), arr.begin() + mid + 1);
return result;
}
else if (mid + 1 < k) {
left = mid + 1;
}
else right = mid - 1;
}
return vector<int>{};
}
int quicksort(vector<int>&arr, int left, int right) {
int labelVal = arr[left];
while (left < right) {
while (left < right && arr[right] >= labelVal)right--;
arr[left] = arr[right];
while (left < right && arr[left] <= labelVal)left++;
arr[right] = arr[left];
}
arr[left] = labelVal;
return left;
}
};
另外暴力排序和计数排序等就不贴了。