求最小的K个数
方法一:利用快排的思想,复杂度为O(n)???
class Solution { public: int Partition(vector<int>& input, int begin, int end) { int low = begin; int high = end; int pivot = input[low]; while (low<high) { while (low<high&&pivot <= input[high]) high--; //input[low] = input[high]; swap(input[low], input[high]); while (low<high&&pivot >= input[low]) low++; //input[high] = input[low]; swap(input[low], input[high]); } input[low] = pivot; return low; } vector<int> GetLeastNumbers_Solution(vector<int> input, int k) { int len = input.size(); if (len == 0 || k>len||k<=0) return vector<int>(); if (len == k) return input; int start = 0; int end = len - 1; int index = Partition(input, start, end); while (index != (k - 1)) { if (index>k - 1) { end = index - 1; index = Partition(input, start, end); } else { start = index + 1; index = Partition(input, start, end); } } vector<int> res(input.begin(), input.begin() + k); return res; } };
方法二:利用堆排序的思想,时间复杂度为O(nlogk)
利用堆排序,特别适用于海量数据中寻找最大或者最小的k个数字。即构建一个大堆容器,初始化大小为k,变量初始数,如初始数组大小小于等于k直接返回,如果大于k,则选择数组的前k个元素,填充堆,然后调整为最大堆。调整完之后,继续从初始数组中拿出一个元素,如果该元素比大堆的堆顶小,则替换堆顶,继续调整为最大堆,如果大于等于堆顶则直接丢弃,不作调整。
PS:大堆还是小堆的选择很重要,不是寻找最小的k个元素就要选择小堆,而且恰恰相反。寻找最小的k个数,其实就是寻找第k个大的元素,即寻找k个数中最大的,不断调整堆,堆得元素个数是k,堆顶是最大值,遍历完初始数组后,堆中存在的元素即使我们所要寻找的k个最小元素。
class Solution { public: vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {if(k<=0||k>input.size()||input.size()==0)return vector<int>(); vector<int>max_heap(k,0); for(int i=0;i<k;i++){ max_heap[i]=input[i]; } for(int i=(k-1)/2;i>=0;i--) maxheap_down(max_heap,i,k-1); for(int i=k;i<input.size();i++){ if(input[i]<max_heap[0]){ max_heap[0]=input[i]; maxheap_down(max_heap,0,k-1); } } return max_heap; } void maxheap_down(vector<int>&a,int start,int end){ int c=start; int value=a[c]; int l=2*c+1; for(;l<=end;c=l,l=2*c+1){ if(l<end&&a[l]<a[l+1])l++; if(value>a[l])break; else{ a[c]=a[l]; a[l]=value; } } } };