问题描述
- 输入:A =[A0,A1,…,A_{n-1}],k < n
- 输出:第 k 小的数(特例:中位数)
基本思路
- 将数组排序,然后访问第 k 个就是第 k 小
- 复杂度主要是排序,最好也需要 O(nlogn)
- 我们只需要找第 k 小,并不需要完全排序的一个结构,是否可以用一点排序的操作,就能找出来呢?
优化方法
- Divide and Conquer 的方法
- 和快速排序的代码框架几乎一样,只不过不需要完全排序,是一个不断递归寻找的过程,一旦寻找到,则完成
- 时间复杂度最好为 O(n),最差为 O(n^2),平均 O(n),这个复杂度和每次选取的pivot的值相关,所以也出现很多选择 pivot 的算法,尽量选择接近中心的pivot。
- BFPRT 算法。median of three
- QuickSelect 算法,随机选取 pivot
- Floyd-Rivest 算法
代码实现
#include<iostream>
#include<vector>
#include<numeric>
using namespace std;
int par(vector<int>& v, int l, int r){
int i = l, j= l;
int pivot = v[r];
while(i<r && j<r){
if(v[j] <= pivot){
swap(v[i],v[j]);
i++;
j++;
}else{
j++;
}
}
swap(v[i],v[r]);
return i;
}
int QuickSelectKth(vector<int>&v, int l, int r, int k){
if(k>r-l+1 || k<1){
cout<<"Invalid search range!";
return 0;
}
int p = par(v,l,r);
int kth = p-l+1;
if(kth == k)
return v[p];
else if(kth > k)
return QuickSelectKth(v,l,p-1,k);
else
return QuickSelectKth(v,p+1,r,k-kth);
}
int main(){
vector<int>v{2,5,7,10,11,4,3,6,8,1,9};
int k = 3;
int res = QuickSelectKth(v,0,v.size()-1,k);
cout<<res;
return 0;
}