您的位置:首页 > Web前端

剑指Offer-40:最小的k个数

2018-03-09 15:28 260 查看

题目:

输入n个整数,找出其中最小的K个数。

例子

例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

链接:

剑指Offer(第2版):P209

思路标签:

算法:快排分区堆排序

数据结构:红黑树

解答:

1. 基于快排Partition函数的算法(时间复杂度:O(n))

基于快排算法中的Partition函数,使得比选中的数字小的数字都在它左边,比选中的数字大的数字都在它的右边。

如果选中的数字的下标刚好是k-1,那么这个数字就是数组中的中位数;

如果它的下标大于k-1,那么中位数应该位于它的左边,继续在左边寻找;

如果它的下标小于k-1,那么中位数应该位于它的右边,继续在右边寻找。

利用递归实现,但是会修改输入数组的顺序,这里需要问清面试官。

class Solution {
public:
void swap(int &i, int &j)
{
if (i == j)
return;
int temp = i;
i = j;
j = temp;
}

int Partition(vector<int> &input, int start, int end)
{
if (input.empty() || start>end) return -1;

int index = rand() % (end - start + 1) + start;
swap(input[index], input[end]);
int small = start - 1;
for (index = start; index<end; ++index)
{
if (input[index] <= input[end])
{
++small;
if (index != small)
swap(input[index], input[small]);
}
}
small++;
swap(input[small], input[end]);
return small;
}

vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
{
vector<int> result;
if (input.empty() || k>input.size() || k <= 0) return result;

int start = 0;
int end = input.size() - 1;
int index = Partition(input, start, end);

while (index != (k - 1))
{
if (index > (k - 1))
{
end = index - 1;
index = Partition(input, start, end);
}
else
{
start = index + 1;
index = Partition(input, start, end);
}
}

for (int i = 0; i<k; ++i)
{
result.push_back(input[i]);
}

return result;
}
};


2. 堆排序,适合处理海量数据(时间复杂度O(nlgk))

利用一个大小为k的数据容器来存储最小的k个数字,如果容器中的数字小于k个,那么直接将数据放入;

如果容器中已经存在k个数字,则用待插入的整数和容器中的最大值进行比较,小于最大值则替换,否则输入下一个数字。

很明显利用最大堆的原理来进行求解。

可以直接利用STL中的set和multiset,二者是利用红黑树实现的。

class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
{
vector<int> result;
int length = input.size();
if (input.empty() || k < 1 || length < k)
return result;

multiset<int, greater<int>> leastNumbers; //从大到小排序的set
multiset<int, greater<int>>::iterator iterGreater; //定义迭代器

vector<int>::const_iterator iter = input.begin();
for (; iter != input.end(); ++iter) {
if (leastNumbers.size() < k)
leastNumbers.insert(*iter);
else {
iterGreater = leastNumbers.begin();

if (*iter < *(iterGreater)) {
leastNumbers.erase(iterGreater);
leastNumbers.insert(*iter);
}
}
}

for (iterGreater = leastNumbers.begin(); iterGreater != leastNumbers.end(); ++iterGreater)
result.push_back(*iterGreater);

return result;
}
};


C++相关

C++ STL set容器常用用法

http://blog.csdn.net/cerberux/article/details/51774121

【C++ STL】Set和Multiset

<
4000
a href="https://www.cnblogs.com/ChinaHook/p/6985444.html">https://www.cnblogs.com/ChinaHook/p/6985444.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息