【剑指offer】54.最小的K个数

总目录:

算法之旅导航目录

 

1.问题描述

给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。
数据范围:0≤k,n≤10000,数组中每个数的大小0≤val≤1000
要求:空间复杂度 O(n) ,时间复杂度 O(nlogk)

 

2.问题分析

 1堆排序

不需要手撕堆排序,用优先队列priority_queue

2快速排序

快速排序,利用快速排序在基准值左侧是有序序列的特性、且其时间复杂度能满足要求。

快速排序的时间复杂度满足要求,空间复杂度为O(1)


3.代码实例

堆排序

 1 class Solution {
 2 public:
 3     vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
 4         vector<int> ret;
 5         if (k==0 || k > input.size()) return ret;
 6 
 7         //使用优先队列
 8         priority_queue<int, vector<int>> pq;//默认大优先
 9         for (const int val : input) {
10             //先插入k个,然后后续选较小值
11             if (pq.size() < k) {
12                 pq.push(val);
13             }
14             else {
15                 if (val < pq.top()) {
16                     pq.pop();
17                     pq.push(val);
18                 }
19 
20             }
21         }
22         
23         while (!pq.empty()) {
24             ret.insert(ret.begin(),pq.top());//因为大优先
25             pq.pop();
26         }
27         return ret;
28     }
29 };

 快速排序

 1 class Solution {
 2   public:
 3     int partition(vector<int>& input, int left, int right) {
 4         int pivot = input[right];//选最后一个元素作基准
 5         int mid = left;//大小分界线,从最左边开始
 6 
 7         //使用cur指针遍历剩余元素
 8         for (int cur = left; cur < right; cur++) {
 9             //如果cur指向的值小于基准值,则应将其放在分界线左侧,而此时分界线指向的值是大于等于基准值的
10             if (input[cur] < pivot) {
11                 swap(input[mid],
12                      input[cur]);//mid指向的是大于等于基准值的,cur指向的是小于基准值的
13                 mid++;//分界线右移动
14             }
15         }
16 
17         //将基准值放到分界线处,将分界线处大于基准值的值放到最后
18         swap(input[mid], input[right]);
19         return mid;
20     }
21 
22     vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
23         vector<int> ret;
24         if (k==0 || k > input.size()) return ret;
25          int left = 0, right = input.size();
26         while (left < right) {
27             int mid = partition(input, left, right-1);
28             //如果已经足够k个有序数字
29             if (mid+1 == k) {
30                 return vector<int>({input.begin(), input.begin()+k});
31             }
32 
33             //排左边还是右边
34             if (mid+1 < k) {
35                 left = mid + 1;
36             }  
37             else {
38                 right = mid;
39             }
40  
41         }
42         return ret;
43     }
44 };
View Code

 

posted @ 2022-11-22 12:15  啊原来是这样呀  阅读(28)  评论(0编辑  收藏  举报