http://ac.jobdu.com/problem.php?cid=1039&pid=13
-
题目描述:
-
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
-
输入:
-
每个测试案例包括2行:
第一行为2个整数n,k(1<=n,k<=200000),表示数组的长度。
第二行包含n个整数,表示这n个数,数组中的数的范围是[0,1000 000 000]。
-
输出:
-
对应每个测试案例,输出最小的k个数,并按从小到大顺序打印。
-
样例输入:
-
8 4
4 5 1 6 2 7 3 8
-
样例输出:
-
1 2 3 4
这道题目可能是有史以来做得最恶心的题目了!题目的意思很简单,就是输出n个数中最小的k个数! 1。开始做,就想着排序,再直接输出k个数,但是,这显然会超时,时间复杂度是O(n*logn); 2。第二种思路是取前k个数,再从后面n - k个元素中找出比前k个元素最大值还小的元素进行交换,时间复杂度是O((n-k)*k)!,不过,数据不弱,还是照样超时! 3。于是尝试第三种思路,利用堆排序的思想,构造前k个元素的大根堆,再在后面的元素中找比堆顶小的元素与堆顶进行交换,第次交换后,对堆顶进行重建堆!这样时间复杂度O(n + k*logk),还是照样超时! 4。第四种思路是找到所有元素中第k大的元素,再扫描一遍,求出比k小的元素,再进行排序,这样时间复杂度同样O(n + k*logk)! 不过 居然可以AC! 以下是AC代码: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <cctype> #include <cstdlib> #include <string.h> #include <algorithm> #include <cmath> #include <set> #include <vector> using namespace std; vector<int> myvector; vector<int>::iterator it; int main () { int i , n , k, p; while(scanf("%d %d",&n,&k) == 2) { myvector.clear(); for(i = 0;i < n;i++) { scanf("%d",&p); myvector.push_back(p); } //random_shuffle (myvector.begin(), myvector.end());//加上这句超时,去掉就可以AC nth_element (myvector.begin(), myvector.begin()+k, myvector.end()); sort(myvector.begin(), myvector.begin()+k); for (it = myvector.begin() ; it < myvector.begin() + k - 1; ++it) printf("%d ",*it); printf("%d\n",*it); } return 0; }