BM46 最小的K个数
描述
给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。数据范围:,数组中每个数的大小
要求:空间复杂度
,时间复杂度
示例1
输入:
[4,5,1,6,2,7,3,8],4
复制返回值:
[1,2,3,4]
复制说明:
返回最小的4个数即可,返回[1,3,2,4]也可以
示例2
输入:
[1],0
复制返回值:
[]
复制
示例3
输入:
[0,1,2,1,2],3
复制返回值:
[0,1,1]
题解
思路:
这里使用快排的思想可以快速找出前k个最小的数。我们知道一次快排的完毕的时候如果此时中间索引为i,那么i左边的元素都小于该索引处的值,其右边的元素都大于该索引处的值。因此,我们可以知道[0,i-1]是前i个最小的元素,如果i == k ,那么[0,i-1]就是我们要找的前k个元素了,实现代码如下:
// 一次快排,返回结束时的索引
int sort_once(std::vector<int> &v, int left, int right)
{
if (left == right)
{
return left;
}
int key = v[left];
while (left < right)
{
while (v[right] >= key && right > left)
{
right--;
}
std::swap(v[left], v[right]);
while (v[left] <= key && left < right)
{
left++;
}
std::swap(v[left], v[right]);
}
v[left] = key;
return left;
}
std::vector<int> GetLeastNumbers_Solution(std::vector<int> input, int k)
{
int left = 0;
int right = input.size() - 1;
while (left <= right)
{
int pos = sort_once(input, left, right);
if (pos == k - 1)
{
right = pos;
break;
}
else if (pos > k - 1)
{
right = pos - 1;
}
else
{
left = pos + 1;
}
}
std::vector<int> v{input.begin(), input.begin() + k};
return v;
}