题:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
方法一:O(n)的算法,不过要改变数组。
思路:利用快排的思想,以最后一个元素为基准,将数组一分为二,左边小于基准,右边大于基准,完成一次趟分割,基准的下标为index,这时,包括基准在内,左边有index+1个最小元素,若index+1=k,显然复合题意,直接将这index+1个元素输出即可,若不等于:
(1)index>k-1,则前k个最小元素的右端点应该在基准的左边,所以更新查找范围的右端点,重新在左侧找;
(2)index<k-1,则前k个最小元素应该包括基准,且其右端点在基准的右边,所以更新查找范围的左端点,重新在左侧找。
代码如下:
1 class Solution { 2 public: 3 vector<int> GetLeastNumbers_Solution(vector<int> input, int k) { 4 vector<int> res; 5 if(input.empty()||k>input.size()||k<=0) 6 return res; 7 int len=input.size(); 8 int start=0; 9 int end=len-1; 10 int index=partition(input,start,end); 11 while(index !=k-1) 12 { 13 if(index>k-1) 14 { 15 end=index-1; 16 } 17 else 18 { 19 start=index+1; 20 } 21 index=partition(input,start,end); 22 } 23 for(int i=0;i<k;i++) 24 { 25 res.push_back(input[i]); 26 } 27 return res; 28 } 29 30 int partition(vector<int> &input,int start,int end) 31 { 32 int pivot=input[end]; 33 int i=start-1; 34 for(int j=start;j<end;j++) 35 { 36 if(input[j]<=pivot) 37 { 38 i++; 39 swap(input[i],input[j]); 40 } 41 } 42 swap(input[i+1],input[end]); 43 return i+1; 44 } 45 };
方法二,就是在博文top k中介绍的方法,开辟大小为k的数组,建立最大堆,然后从n个元素中剩下的任取一个和堆顶元素比较,若小于则更新堆,不小于就不用管。不用改变原数组,时间复杂度为O(nlogk)
另外,值得注意的是:
方法一中使用快排的思想找下标index的过程,最后找到的index所在位置也是数中第K大的数,所以找数组中任意第K大的数的时间复杂度亦为O(n)。