您的位置:首页 > 其它

《Cracking the Coding Interview》——第18章:难题——题目6

2014-04-29 03:05 357 查看
2014-04-29 02:27

题目:找出10亿个数中最小的100万个数,假设内存可以装得下。

解法1:内存可以装得下?可以用快速选择算法得到无序的结果。时间复杂度总体是O(n)级别,但是常系数不小。

代码:

// 18.6 Find the smallest one million number among one billion numbers.
// Suppose one billion numbers can fit in memory.
// I'll use quick selection algorithm to find them. This will return an unsorted result.
// Time complexity is O(n), but the constant factor may be massive. I don't quite like this algorithm.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

const int CUT_OFF = 3;

int medianThree(vector<int> &v, int ll, int rr)
{
int mm = (ll + rr) / 2;

if (v[ll] > v[mm]) {
swap(v[ll], v[mm]);
}
if (v[ll] > v[rr]) {
swap(v[ll], v[rr]);
}
if (v[mm] > v[rr]) {
swap(v[mm], v[rr]);
}
swap(v[mm], v[rr - 1]);
return v[rr - 1];
}

void quickSelect(vector<int> &v, int ll, int rr, int k)
{
// reference from "Data Structure and Algorithm Analysis in C" by Mark Allen Weiss.
int pivot;
int i, j;

if (ll + CUT_OFF <=    rr) {
pivot = medianThree(v, ll, rr);
i = ll;
j = rr - 1;

while (true) {
while (v[++i] < pivot);
while (v[--j] > pivot);
if (i > j) {
break;
}
swap(v[i], v[j]);
}
swap(v[i], v[rr - 1]);

if (k < i) {
return quickSelect(v, ll, i - 1, k);
} else if (k > i) {
return quickSelect(v, i + 1, rr, k);
}
} else {
for (i = ll; i <= rr; ++i) {
for (j = i + 1; j <= rr; ++j) {
if (v[i] > v[j]) {
swap(v[i], v[j]);
}
}
}
}
}

int main()
{
vector<int> v;
vector<int> res;
int n, k;
int i;
int k_small, count;

while (cin >> n >> k && (n > 0 && k > 0)) {
v.resize(n);
for (i = 0; i < n; ++i) {
cin >> v[i];
}

// find the kth smallest number
// this will change the order of elements
quickSelect(v, 0, n - 1, k - 1);
k_small = v[k - 1];
count = k;
for (i = 0; i < n; ++i) {
if (v[i] < k_small) {
--count;
}
}
for (i = 0; i < n; ++i) {
if (v[i] < k_small) {
res.push_back(v[i]);
} else if (v[i] == k_small && count > 0) {
res.push_back(v[i]);
--count;
}
}

cout << '{';
for (i = 0; i < k; ++i) {
i ? (cout << ' '), 1 : 1;
cout << res[i];
}
cout << '}' << endl;

v.clear();
res.clear();
}

return 0;
}


解法2:如果要求结果也是有序的,那可以用最大堆得到有序结果。时间复杂度是O(n * log(m))级别,思路和代码相比快速选择算法都更简单,不过效率低了些。

代码:

// 18.6 Find the smallest one million number among one billion numbers.
// Suppose one billion numbers can fit in memory.
// I'll use a max heap, which runs in O(n * log(k)) time, returns a sorted result.
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

template <class T>
struct myless {
bool operator () (const T &x, const T &y) {
return x < y;
};
};

int main()
{
int val;
int n, k;
int i;
// max heap
priority_queue<int, vector<int>, myless<int> > q;
vector<int> v;

while (cin >> n >> k && (n > 0 && k > 0)) {
k = k < n ? k : n;
for (i = 0; i < k; ++i) {
cin >> val;
q.push(val);
}

for (i = k; i < n; ++i) {
cin >> val;
if (q.top() > val) {
q.pop();
q.push(val);
}
}
while (!q.empty()) {
v.push_back(q.top());
q.pop();
}
reverse(v.begin(), v.end());

cout << '{';
for (i = 0; i < k; ++i) {
i ? (cout << ' '), 1 : 1;
cout << v[i];
}
cout << '}' << endl;

v.clear();
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐