问题描述
输入: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 ;
}