每日一练:快排-最小k个数
面试题 17.14. 最小K个数 - 力扣(LeetCode)
题目要求:
设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。
示例:
输入: arr = [1,3,5,7,2,4,6,8], k = 4 输出: [1,2,3,4]
提示:
0 <= len(arr) <= 100000
0 <= k <= min(100000, len(arr))
快速排序 O(N):
快速排序可将数组分为3段:
设区间1的长度为a,区间2的长度为b,区间c的长度为c;a、b、c与可能具有以下大小关系:
(1)若a>k,则最小k个数在区间1中,以[sta,left]继续分割
(2)若a+b>=k,则最小k个数包含区间1和区间2(部分或全部),因为区间2中的元素都等于k,所以返回区间[sta,right-1]的前k个元素即可。
(3)若a+b+c>=k,则最小k个数包含区间1、2和3(部分或全部),此时可以先将区间1、2的所有元素保存起来,然后以[right,end]继续分割,但是只需要找前k-a-b个元素。
class Solution {
vector<int> ret;
vector<int> _smallestK(vector<int>& arr, int sta, int end, int k) {
if (sta >= end)
return ret;
int key = arr[rand() % (end - sta + 1) + sta];
int left = sta - 1, right = end + 1, cur = sta;
while (cur < right) {
if (arr[cur] == key)
cur++;
else if (arr[cur] < key)
swap(arr[++left], arr[cur++]);
else if (arr[cur] > key)
swap(arr[--right], arr[cur]);
}
int a = left - sta + 1, c = end - right + 1,
b = (end - sta + 1) - (a + c);
if (a > k) {
return _smallestK(arr, sta, left, k);
} else if (a + b >= k) {
for (int i = sta; i < sta + k; i++) {
ret.push_back(arr[i]);
}
return ret;
} else {
for (int i = sta; i < sta + a + b; i++) {
ret.push_back(arr[i]);
}
return _smallestK(arr, right, end, k - a - b);
}
}
public:
vector<int> smallestK(vector<int>& arr, int k) {
if (k == 0)
return {};
return _smallestK(arr, 0, arr.size() - 1, k);
}
};
原文地址:https://blog.csdn.net/2303_78095330/article/details/144305741
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!