【LeetCode & 剑指offer刷题】查找与排序题2:40 最小的k个数(对应Kth Largest Element in an Array)
【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)
40 最小的k个数
题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,
/*
//暴力法:sort, O(nlogn)
//方法一:使用自带的stl函数
#include <algorithm>
using namespace std;
class Solution
{
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
{
if(k<=0 || k > input.size()) return vector<int>(); //处理非法输入
nth_element(input.begin(), input.begin()+k-1, input.end());
vector<int> result(input.begin(),input.begin()+k); //构造结果向量
return result;
}
};*/
/*
/*掌握
方法一:基于partition函数(快排中有用到,stl中也有,但是还是自己实现较好)
多次partition直到枢轴位置为k即可
缺点:会改变输入数组的元素位置
平均O(n),每次partition 平均O(n),次数未知,真的是O(n)吗,存疑?
思考:最好情况为O(n),最坏情况为O(n^2)(如对于倒序排列的数组)
通过优化partition,比如三数中值枢轴法或随机初始化枢轴法,可以改善时间复杂度
分析参考:
考虑最坏情况下,每次 partition 将数组分为长度为 N-1 和 1 的两部分,然后在长的一边继续寻找第 K 大,此时时间复杂度为 O(N^2 )。
不过如果在开始之前将数组进行随机打乱,那么可以尽量避免最坏情况的出现。
而在最好情况下,每次将数组均分为长度相同的两半,运行时间 T(N) = N + T(N/2),时间复杂度是 O(N)。
*/
#include <cstdlib>
class
Solution
{
public
:
vector
<
int
>
GetLeastNumbers_Solution
(
vector
<
int
>
input
,
int
k
)
{
if
(
input
.
empty
()
||
k
<=
0
||
k
>
input
.
size
())
return
vector
<
int
>();
//处理异常输入
int
left
=
0
,
right
=
input
.
size
()-
1
;
int
pivot_pos
;
while
(
left
<=
right
)
//类似二分查找法
{
pivot_pos
=
partition
(
input
,
left
,
right
);
//如果要求最大的第k个数,可以对partition函数进行改造
if
(
pivot_pos
<
k
-
1
)
left
=
pivot_pos
+
1
;
else
if
(
pivot_pos
>
k
-
1
)
right
=
pivot_pos
-
1
;
else
break
;
//此题要求的是返回最小的前k个数,如果仅返回最小的第k个数,直接在这里return a[pivot_pos]即可
}
vector
<
int
>
result
(
input
.
begin
(),
input
.
begin
()+
k
);
//构造结果向量
return
result
;
}
private
:
int
partition
(
vector
<
int
>&
a
,
int
left
,
int
right
)
{
//随机初始化枢轴 5ms