【问题】输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
【思路】很多人都觉得这个问题是一个排序问题,但我觉得不一定要排序啊,可以使用堆结构(最小堆),首先将所有的元素都压入到最小堆中,每次弹出最小值就好了,一共弹出k个数。直接使用STL库中的堆结构,也就是优先级队列!代码就非常简洁了!
class Solution { public: vector<int> GetLeastNumbers_Solution(vector<int> input, int k) { priority_queue<int, vector<int>, greater<int>> pq; vector<int> res; if(input.size() < k) return res; // 返回数值内存大于输入内存,则返回空 for(auto i: input){ pq.push(i); } while(k--){ res.push_back(pq.top()); pq.pop(); } return res; } };
当然,只会用库在面试官面前是不行的,接下来我们手动使用vector实现一个最小堆!
文章链接: 从底层实现堆结构和堆排序
这里面我将上面文章中的最大堆改成了最小堆,右一个细节就是:heapify中有一个left+1的边界,如果不满足这个边界,那么必须返回left,而不是left+1。
class Solution { public: void heapInsert(vector<int>& list, int index){ while(list[index] < list[(index-1)/2]){ swap(list[index], list[(index-1)/2]); // 与根节点交换 index = (index-1)/2; // 当前位置更新 } } // 改变某个值,仍然是最小堆结构 void heapify(vector<int>& list, int index, int heapSize){ int left = index*2+1; while(left < heapSize){ int mini = (left + 1) < heapSize && list[left] > list[left+1] ? left + 1 : left; // 这个判断错误时只能是left,由于left+1可能出了索引范围 mini = list[mini] < list[index] ? mini : index; if(mini == index){ break; } swap(list[mini], list[index]); index = mini; left = index*2+1; } } vector<int> GetLeastNumbers_Solution(vector<int> input, int k) { vector<int> res; if(input.size() == 0) return res; if(input.size() < k) return res; for(int i = 0;i < input.size(); i++){ heapInsert(input, i); } int heapSize = input.size(); while(k--){ res.push_back(input[0]); swap(input[0], input[--heapSize]); heapify(input, 0, heapSize); } return res; } };