题目:
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
思路:
sort排序后直接打印前 k 个数 , 时间复杂度为 nlogn 。
创建一个容量为k的大根堆的优先队列 ,遍历数组, 同时维护这个大根堆 。时间复杂度为O(nlogK);
进阶:
要求不能用全局排序 , 要求时间复杂度达到最低 , 要求不能用辅助空间。
思路:
快排思想:
对于快排 , 我们知道每一趟快排都可以确定一个元素在排序后的正确位置 , 设这个被确定的元素为 p ,但 p + 1 == k 时说明下标为p的元素已经排序好位置是数组的第K小 , 根据快排确定后 , p 的左边所有元素都会小于 p , 所有原数组从 0 到 p 的所有元素 就是要输出的正确答案。如果 p + 1 大于k 或者小小于 k 可以用二分来确定下一次我们要定位的元素小标 , 直到 p + 1 == k 。
空间复杂度: 原地修改数组的元素 , 所有O(0);
时间复杂度 : 每一次定位p 的 数据大小为 n + n/2 + n/4 + … = 2n 每次都舍弃上次数据的二分之一 , 最快一次就能定位出来 O(n) 最坏为O(n*n) 平均复杂度为O(n);
代码:
#include<bits/stdc++.h>
using namespace std;
int quickSort(vector<int>& arr , int l , int r){
int base = arr[r];
int i = l;
for(int j = l ; j < r ; ++j){
if(arr[j] < base){
swap(arr[i++] , arr[j]);
}
}
swap(arr[i] , arr[r]);
return i;
}
vector<int> solution(vector<int>& arr , int k ){
if(k == 0 || k > arr.size())return {};
int l = 0 , r = arr.size() - 1;
while(l <= r){
int p = quickSort(arr , l , r);
if(p + 1 == k)return {arr.begin() , arr.begin() + k};
if(p + 1 > k)r = p - 1;
else l = p + 1;
}
return {};
}
/*int solution2(vector<int>& arr , int k ){
if(k == 0 || k > arr.size())return -1;
int l = 0 , r = arr.size() - 1;
while(l <= r){
int p = quickSort(arr , l , r);
if(p + 1 == k)return arr[p];
if(p + 1 > k)r = p - 1;
else l = p + 1;
}
return -1;
}*/
int main()
{
vector<int>arr{5,1,6,3,7,2,8 ,3, 4};
int k = 1;
vector<int>ans = solution(arr , k);
for(int v : ans){
cout << v << " ";
}
cout << endl;
cout << "-------------------"<<endl;
cout << solution2(arr , 4);
return 0;
}