剑指offer 面试题30—最小的k个数
来源:互联网 发布:淘宝联盟代码怎么用 编辑:程序博客网 时间:2024/05/14 13:45
题目:
输入n个整数,找出其中最小的k个数,例如输入4,5,1,6,2,7,3,8这个8个数字,则最小的4个数字是1,2,3,4.
基本思想:
解法一:先排序再找K:O(nlgn)
最简单的方法就是把它排序,然后找出前面的k个数字就是最小的k个数字,这种思路的时间复杂度是O(nlgn)解法二:partition函数:O(n)
利用快速排序的partition函数来将数组分成两部分,partition函数的返回值就是排序好的数组的最终下标,其左边是比它小的数,右边是比它大的数,这样我们只需要将partition的返回值与k做比较,如果与k相等,则返回(返回的k个数字不一定是排序的);如果比k大,则最小的k个数在左边,则继续返回递归;如果比k小,则最小的k个数中有一部分在右边,则返回这部分到右边寻找。
#include <iostream> using namespace std; int par(int a[],int len,int low,int high) { int t=a[low]; int i=low,j=high; while(i!=j) { while(i<j&&a[j]>=t) j--; while(i<j&&a[i]<=t) i++; if(i<j) { int temp=a[i]; a[i]=a[j]; a[j]=temp; } } a[low]=a[i]; a[i]=t; return i; } void foo(int a[],int len,int k) { if(len<=0) return ; int start=0; int end=len-1; int index=par(a,len,start,end); while(index!=k-1) { if(index>k-1) { end=index-1; index=par(a,len,start,end); } else { start=index+1; index=par(a,len,start,end); } } for(int i=0;i<k;i++)cout<<a[i]<<" ";cout<<endl; } int main() { int a[]={4,5,1,6,2,7,3,8}; int k=4; int len = sizeof(a)/sizeof(a[0]); foo(a,len,k); return 0; }
解法三:海量数据:O(nlgk)
我们可以先创建一个大小为K的数据容器来存储最小的K个数,接下来我们每次从输入的n个整数中读入一个数,如果容器中已有的数字少于K,则直接把这次读入的整数放入容器中;如果容器中已有K个数,就是容器满了,此时我们不能插入新的数字而只能替换已有的数字了。找出这K个数的最大值,然后拿这次待插入的整数和最大值相比较。如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还大,那么这个数不可能是最小的K个整数之一,于是我们可以抛弃这个数。
我们可以用二叉树(红黑树或最大堆)来实现这个数据容器。堆查找最大值O(1),删除插入为O(logk);红黑树查找、删除和插入都是O(logk)。
第2种情况非常适合海量数据的处理,当n>>k的时候非常适合。
时间复杂度为:O(n*lgk)
typedef multiset<int, greater<int> > intSet;typedef multiset<int, greater<int> >::iterator setIterator;void GetLeastNumbers_Solution2(const vector<int>& data, intSet& leastNumbers, int k){ leastNumbers.clear(); if(k < 1 || data.size() < k) return; vector<int>::const_iterator iter = data.begin(); for(; iter != data.end(); ++ iter) { if((leastNumbers.size()) < k) leastNumbers.insert(*iter); else { setIterator iterGreatest = leastNumbers.begin(); if(*iter < *(leastNumbers.begin())) { leastNumbers.erase(iterGreatest); leastNumbers.insert(*iter); } } }}
解法二与解法三比较:
解法二是基于Partition其时间复杂度为O(n),比解法三要快,但是解法二是有限制的,它改变了原始数组,如果要求不能改变数组的话,就不适用解法二了。
解法三虽然慢了点,但他是有优点的,1.没有改变数组,2.使用于海量数据,如果数据量特别大,那么一次可能不能把所有数据都读入内存,那么这样的话解法二是明显不行的,因它要把所有数据都存如内存才能再做转化和比较,然而解法三就会特别适合,因为他是一个个读数据,并且容器中只存k个数,所以他是适用的。
- 剑指offer 面试题30—最小的k个数
- 剑指offer面试题30最小的k个数
- [剑指offer][面试题30]最小的k个数
- 【剑指offer】面试题30:最小的K个数
- 剑指Offer:面试题30 最小的k个数
- 剑指offer:面试题30,求最小的K个数
- 剑指offer 面试题30 最小的K个数
- 【剑指Offer学习】【面试题30:最小的k个数】
- 剑指offer-面试题30:最小的K个数
- 剑指offer之面试题30:最小的k个数
- 剑指offer之面试题30最小的k个数
- 剑指Offer----面试题30:最小的K个数
- 剑指offer-----面试题30(最小的k个数)
- 剑指offer面试题30:最小的K个数
- 剑指offer--面试题30:最小的K个数
- 剑指Offer之面试题30:最小的K个数
- 剑指offer-面试题30-最小的k个数
- 剑指Offer系列-面试题30:最小的K个数
- 三种字符编码:ASCII、Unicode和UTF-8
- 反转链表
- 关于c中指针传参的问题
- CreateThread
- [学习总结][基础篇]Spring(五)
- 剑指offer 面试题30—最小的k个数
- 判断链表是否有环
- 用CocoaPods做iOS程序的依赖管理
- 栈的基本用法(顺序存储结构)
- 高斯消元模板
- PHP文件型缓存解决方案secache
- 反思 并查集
- MTK android内核独立模块编译与加载
- linux_driver_model_devtmpfs