剑指offer——面试题30:最小的k个数
2015-08-27 17:27
495 查看
题目描述:
输入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个数,并按从小到大顺序打印。
样例输入:
样例输出:
思路1我们通过快排找到第k个数,然后比他的小的都在左边,比他大的都在右边
这个是O(n)的算法,只不过这样做的话会修改输入的数组
思路2:
可以用一个容器存储前面k个数,然后后面的数与这个容器中的最大数作比较,然后若是比这个数大或者相等就不管,接着往后遍历
若是比这个数小就替换掉这个数。
算法复杂度:
这里可以采用最大堆,或者红黑树来存储这个k个数,这样查找最大值时就是O(1)的时间复杂度,但查找和删除时需要O(logk),
而遍历n所以时间复杂度为O(nlogk)。
输入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
思路1我们通过快排找到第k个数,然后比他的小的都在左边,比他大的都在右边
这个是O(n)的算法,只不过这样做的话会修改输入的数组
#include<iostream> using namespace std; void change(int numbers[],int i,int j) { int temp=numbers[i]; numbers[i]=numbers[j]; numbers[j]=temp; } int partion(int numbers[],int start,int end) { if(start==end) return start; int temp=numbers[end]; int i=start; int j=end; while(i<j) { while(i<j&&numbers[i]<=temp) i++; change(numbers,i,j); while(i<j&&numbers[j]>=temp) j--; change(numbers,i,j); } return i; } int numer_k(int numbers[],int len,int k) { if(numbers==NULL||k<=0||k>=len) return 0; int start=0; int end=len-1; int index=partion(numbers,start,end); cout<<"index="<<index<<endl; for(int i=0;i<len;i++) cout<<numbers[i]<<' '; cout<<endl; while(index!=k-1) { if(index<k-1) { start=index+1; end=end; index=partion(numbers,start,end); cout<<"index="<<index<<endl; for(int i=0;i<len;i++) cout<<numbers[i]<<' '; cout<<endl; } else { end=index-1; start=start; index=partion(numbers,start,end); cout<<"index="<<index<<endl; for(int i=0;i<len;i++) cout<<numbers[i]<<' '; cout<<endl; } } return numbers[index]; } int main() { int ary[8]={4,5,1,6,2,7,3,8}; cout<<numer_k(ary,8,4)<<endl; system("pause"); }
思路2:
可以用一个容器存储前面k个数,然后后面的数与这个容器中的最大数作比较,然后若是比这个数大或者相等就不管,接着往后遍历
若是比这个数小就替换掉这个数。
算法复杂度:
这里可以采用最大堆,或者红黑树来存储这个k个数,这样查找最大值时就是O(1)的时间复杂度,但查找和删除时需要O(logk),
而遍历n所以时间复杂度为O(nlogk)。
#include<iostream> #include<set> #include<vector> using namespace std; int number_k(vector<int>& vec,int k) { if(vec.empty()) return 0; int len=vec.size(); if(len<k||k<=0) return 0; multiset<int,greater<int> > mu; vector<int>::const_iterator i=vec.cbegin(); for(int j=0;j<k;j++) {mu.insert(*i);i++;} while(i!=vec.end()) { int a=*i; int b=*mu.begin(); if(a<b) { mu.erase(b); mu.insert(a); } i++; } return *mu.begin(); } int main() { int ary[8]={4,5,1,6,2,7,3,8}; vector<int> vec(ary,ary+8); cout<<number_k(vec,4)<<endl; system("pause"); }
相关文章推荐
- 一道阿里面试题(js)
- 黑马程序员 多线程通信
- 黑马程序员——java基础——ServerSocket、Socket构造方法解析
- 阿里巴巴前端三次面试的亲身经历(转)
- 剑指offer——面试题29:数组中出现次数超过一半的数
- 黑马程序员——多线程
- 黑马程序员——IO流
- 程序员面试笔试宝典——读书笔记2、内存分配、sizeof、指针
- 面试题31连续数组的最大和
- 黑马程序员——java基础——管道流
- 设计模式面试
- 黑马程序员_集合框架(一)
- 面试题30 最小的K个数
- 一道SQL面试例题 if...else 与聚集函数
- 黑马程序员--应用:类的创建练习
- 黑马程序员--手机类的例子
- C# SQL 面试题自我总结
- 面试题29数组中出现次数超过一半的数字
- 程序员面试笔试宝典——读书笔记1、程序设计基础知识
- 黑马程序员——java基础 集合 (复习)