最小的k个数
2016-07-14 19:27
330 查看
输入n个整数,找出其中最小的k个数。例如输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
解法一(平均时间复杂度为O(n)):
思想:基于partion函数来解决这个问题。如果基于数组的第k个数字来调整,使得比第k个数字小的所有数字都位于数组的左边,比第k个数字大的所有数字都位于数组的右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数字(这k个数字不一定是排序的)。
C++代码:
运行结果:3、2、1、4.
注:partition函数会调整数组中数字的顺序。
解法二(时间复杂度为O(nlogk)):
思想:用multiset保存最小的k个数字。每次读入一个数,如果容器中已有的数字少于k个,则直接把这次读入的整数放入容器之中;如果容器中已有k个数字,则比较读入的数字和容器中最大的数字,如果前者大,则在容器中用前者替换后者;如果后者大,则前者不可能是最下的k个数之一。
C++ 代码:
运行结果:4、3、2、1
两种算法的比较:
(1)第一中算法平均时间复杂度为O(n),比第二种思路快,但它会修改输入的数组。
(2)第二种算法不必一次载入所有的数据到内存,适合从海量的数据中找出最小的k个数。
解法一(平均时间复杂度为O(n)):
思想:基于partion函数来解决这个问题。如果基于数组的第k个数字来调整,使得比第k个数字小的所有数字都位于数组的左边,比第k个数字大的所有数字都位于数组的右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数字(这k个数字不一定是排序的)。
C++代码:
#include <iostream> #include <vector> using namespace std; //快速排序的partition函数 int partition(vector<int> &input, int low, int high) { int pivotkey = input[low]; while (low <high) { while (low < high && pivotkey <= input[high]) --high; input[low] = input[high]; while (low < high && pivotkey >= input[low]) ++low; input[high] = input[low]; } input[low] = pivotkey; return low; } //在数组input中找到最小的k个数,结果保存在output中 void getLeastNumber(vector<int> &input, vector<int> &output, int k) { int n = input.size(); if (0 == n || k >n || k<=0) return; int low = 0; int high = n-1; int index = partition(input, low, high); //下标为index的不是第k小的数 while (index +1 != k) { //第k个数在index的右边 if (index+1 < k) { low = index+1; index = partition(input, low, high); } else { high = index - 1; index = partition(input, low, high); } } for (int i=0;i<k;++i) { output.push_back(input[i]); } } int main() { vector<int> input; input.push_back(4); input.push_back(5); input.push_back(1); input.push_back(6); input.push_back(2); input.push_back(7); input.push_back(3); input.push_back(8); vector<int> output; getLeastNumber(input, output, 4); for (int i=0;i<output.size();++i) { cout<<output[i]<<' '; } cout<<endl; return 0; }
运行结果:3、2、1、4.
注:partition函数会调整数组中数字的顺序。
解法二(时间复杂度为O(nlogk)):
思想:用multiset保存最小的k个数字。每次读入一个数,如果容器中已有的数字少于k个,则直接把这次读入的整数放入容器之中;如果容器中已有k个数字,则比较读入的数字和容器中最大的数字,如果前者大,则在容器中用前者替换后者;如果后者大,则前者不可能是最下的k个数之一。
C++ 代码:
#include <iostream> #include <set> #include <vector> using namespace std; typedef multiset<int, greater<int>> intSet; //这里我们采用递减排序。默认的是less<key>,默认采用的是递增排序 typedef multiset<int, greater<int>>::iterator setIterator; //在data中寻找最小的k个数保存到leastNumbers中 void getLeastNumbers(const vector<int> &data, intSet &leastNumbers, int k) { leastNumbers.clear(); if (k<1 || data.size() < k) return; vector<int>::const_iterator it = data.begin(); for (;it!=data.end();++it) { //如果leastNumbers中少于k个数 if (leastNumbers.size() < k) { leastNumbers.insert(*it); } else { //如果该数比leastNumbers中最大的数小,则替换 if (*it < *(leastNumbers.begin())) { leastNumbers.erase(leastNumbers.begin()); leastNumbers.insert(*it); } } } } int main() { vector<int> input; input.push_back(4); input.push_back(5); input.push_back(1); input.push_back(6); input.push_back(2); input.push_back(7); input.push_back(3); input.push_back(8); intSet output; getLeastNumbers(input, output, 4); for (setIterator it=output.begin();it!=output.end();++it) { cout<<*it<<' '; } cout<<endl; return 0; }
运行结果:4、3、2、1
两种算法的比较:
(1)第一中算法平均时间复杂度为O(n),比第二种思路快,但它会修改输入的数组。
(2)第二种算法不必一次载入所有的数据到内存,适合从海量的数据中找出最小的k个数。
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法