题目
从100w个数中找出前100个大的数.
思路
- 取前m个元素(例如m=100),建立一个小顶堆。保持一个小顶堆得性质的步骤,运行时间为O(lgm);建立一个小顶堆运行时间为m*O(lgm)=O(m lgm);
- 顺序读取后续元素,直到结束。每次读取一个元素,如果该元素比堆顶元素小,直接丢弃 如果大于堆顶元素,则用该元素替换堆顶元素,然后保持最小堆性质。最坏情况是每次都需要替换掉堆顶的最小元素,因此需要维护堆的代价为(N-m)*O(lgm); 最后这个堆中的元素就是前最大的10W个。时间复杂度为O(N lgm)。
解法
模拟100个数取前10个数
#include <iostream>
#include "stdlib.h"
#include <vector>
#include <algorithm>
using namespace std;
vector<int> adjustHeap(vector<int>& is, int v, int len);
vector<int> createHeap(vector<int>& is, int len) {
if(is.size() <= 1 || len <= 1) return is;
int root = (len - 1 -1 ) >> 1;
for( ; root >= 0; root--) {
adjustHeap(is, root, len);
}
return is;
}
vector<int> adjustHeap(vector<int>& is, int v, int len) {
int child = v * 2 + 1;
while(child < len) {
if (child + 1 < len && is[child] > is[child + 1]) {
child += 1;
}
if (is[v] > is[child]) {
swap(is[v], is[child]);
v = child;
child = v * 2 + 1;
} else {
return is;
}
}
return is;
}
vector<int> topK(vector<int>& is, int k) {
vector<int> rs = createHeap(is, k);
for (int i = k + 1; i < is.size(); i++) {
if (is[i] > is[0]) {
is[i] = is[0];
adjustHeap(is, 0, k);
}
}
vector<int> ret(rs.begin(), rs.begin() + k);
return ret;
}
int main() {
vector<int> is;
const int N = 100;
while(is.size() < N) {
is.push_back(rand());
}
vector<int> ret = topK(is, 10);
for(auto &j: ret) {
cout << j << ",";
}
cout << endl;
return 0;
}