【数据结构与算法】寻找最大的K个数
来源:互联网 发布:公司网络电脑管理制度 编辑:程序博客网 时间:2024/05/22 14:08
腾讯一面遇到这个题,发现这个题真的是比较经典,打算在这里好好总结一下。
参考自师姐的博文:http://blog.csdn.net/xiaxia__/article/details/44965455(XIAXIA_的专栏)
题目简介:
有很多无序的数,我们姑且假定他们各不相等,怎么选出其中最大的K个数呢?
解法一:直接排序
第一反应,假设有N个数,我们使用一个N个长度的数组将其存储下来,并且使用排序算法将其从大到小依次排列。排序完成后,输出前K个数。如果N不小,但是也不大,比如几千什么的,可以采用快速排序来完成。
复杂度分析:
快速排序平均的复杂度为O(NlogN)。
解法二:部分排序
简单分析一下,我们就能发现解法一的一个明显不足之处,那就是我们将所有的元素都进行了排序,而题目要求只是寻找最大的K个数,也就是说我们只要将最大的K个数排好序就好了,没必要将剩下的N-K个数也进行排序。
在这里,我们可以使用快速排序来完成这个部分排序的功能。在快速排序中,每一轮都需要选定一个pivot,每一轮排序完成后,比pivot大的数都排在它前面,而比pivot小的数都排在它的后面。假设前面的序列为Sa,后面的序列为Sb,Sa的长度为n。
此时有三种情况:
1)当n>K时,我们直接输出Sa的前K个元素就好了;
2)当n=K时,我们直接输出Sa这个序列;
3)当n<K时,我们就需要从Sb中找出K−n个元素和Sa一起输出就好了。
完整测试代码如下:
#include <iostream> #include <ctime>#include <cstdlib>using namespace std; void kBig(int *pArray, int low, int high, int K);int partion(int *pArray, int low, int high);int main() { srand((unsigned)time(NULL)); int data[50];int K = 3, i;for(i = 0; i < 50; i++){data[i] = rand() % 200;cout << data[i] << " ";}cout << endl; kBig(data, 0, 50 - 1, K);for (i = 0; i < K; i++) cout << data[i] << endl;return 0;} //将前K大个数移到数组前K个位置上void kBig(int *pArray, int low, int high, int K){ int index, n; if (low <= high) { //对数组进行划分,并返回划分的位置 index = partion(pArray, low, high); n = index - low + 1; //Sa的个数 if (n == K) //如果恰好是K个的话,那么返回 return; if (n < K) //如果Sa的个数不够的话,那么再从Sb中找K-n个 kBig(pArray, index + 1, high, K - n); if (n > K) //如果Sa的个数大于K的话,那么就从Sa里面返回K个 kBig(pArray, low, index, K); }}//快速排序的划分函数并返回pivot的坐标int partion(int *data, int left, int right){if(left >= right)return left;int pivot;pivot = data[left];while(left < right){while(right > left && data[right] <= pivot)right--;data[left] = data[right];while(right > left && data[left] >= pivot)left++;data[right] = data[left];}data[left] = pivot; return left;}
复杂度分析:
复杂度为O(N)。
解法三:堆排序
如果N是一个较大的数,那用这么大的数组来存储并进行快排,这就是非常不明智地做法了。此时我们可以使用一个大小为K的最小堆来完成。完整测试代码如下:
#include <iostream> #include <ctime>#include <cstdlib>using namespace std; void PercDown(int *data, int i, int N){int tmp, child;child = i << 1;for(tmp = data[i]; child <= N;){if(child + 1 <= N && data[child + 1] < data[child] )child++;if(data[child] >= tmp)break;data[i] = data[child];i = child;child = i << 1;}data[i] = tmp;}void BuildHeap(int *data, int N){int i;for(i = N / 2; i > 0; --i)PercDown(data, i, N);}int main() { srand((unsigned)time(NULL)); int data[50];int sortheap[11] = {0};int K = 10, i;for(i = 0; i < 50; i++){data[i] = rand() % 200;if(i < 10)sortheap[i + 1] = data[i];cout << data[i] << " ";}cout << endl;BuildHeap(sortheap, 10); //建立大小为K的最小堆for(i = 10; i < 50; ++i){if(data[i] > sortheap[1]) //遍历剩下的元素,如果大于根节点就赋值到根节点,然后下滤{sortheap[1] = data[i];PercDown(sortheap, 1, 10);}}for (i = 1; i < 11; i++) cout << sortheap[i] << " ";cout << endl;return 0;}
复杂度分析:O(NlogK)可以看到堆排序这种做法并没有怎么提高时间复杂度,但是却极大的降低了对空间的存储要求,只需要维护一个K大小的堆。
对于堆排序,需要牢记的是 下滤(PercDown) 这个函数,有了这个函数,我们可以轻易实现 BuildHeap,DeleteMin的操作。此外,PercDown 这个函数还很契合我们当前的这个用法。
解法四:计数排序法
适用情况:如果所有N个数都是正整数,且他们的取值范围不大,我们知道最大的数是MAXN。那么我们可以申请一个数组count[MAXN] 来记录每个数出现的次数。然后我们就可以找出最大的K个数。
复杂度:O(N)
- 【数据结构与算法】寻找最大的K个数
- 寻找最大的K个数(TOP K算法)
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的k个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的k个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- Qt::FocusPolicy的使用
- Linux下使用Shell根据txt文件批量创建目录
- 按home键后,重新打开软件后2-3秒钟显示上次的页面
- xshell 实现windows 和linux 命令传输文件
- C++ map排序(按照value值排序)
- 【数据结构与算法】寻找最大的K个数
- jbpm-6.3.0.Final-installer-full在Windows上的部署、数据库由H2切换为MySql、Linux上的部署全过程
- jQuery序列化表单 serialize() serializeArray()
- 第一次启动GRASS GIS和一些入门资源
- Centos 6.6上安装Git Lab服务及问题总结
- 给Python初学者的一些技巧
- Material Design 系列 Transition
- GFS
- Android TextView(价格)文字底部或者中间 加横线