问题:给定n个整数,如何用最快的方法求出第k大的数?

  我们当然可以对这n个整数排序然后直接输出第k大的数,时间复杂度为O(nlog n)。
  但是实际上我们可以用基于快速排序所用到的思想,在每一层递归中,随机选取一个数为基准值,把比它大的数交换到左半段,把其余的数和基准值自身一起作为右半段。在这个过程中假设统计出比基准值大的数有cnt个,若k<=cnt,就在左半段中递归寻找第k大;若k>cnt,就在右半段中递归寻找第k-cnt大的数。递归边界为这一段区间长度为1。就返回这个数即为最初所找区间第k大的数。
  因为是随机选取基准值,所以找第k大的数平均时间复杂度为n + n/2 + n/4 + ... + 1 = O(n)。
总的时间复杂度即为O(n)
实现代码:

#include<bits/stdc++.h>
using namespace std;
int a[100010];
void swap(int& x, int& y) {
    int temp = x;
    x = y;
    y = temp;
}
int random(int l, int r) {//返回一个在[l,r]范围内的随机整数
    return rand() % (r - l + 1) + l;
}
int find_kth(int l, int r, int k) {
    if (l == r)return a[l];//递归边界
    int temp = a[random(l, r)];//随机选取主元
    int cnt = 0;//计比主元大的个数
    int i = l, j = r;
    while (i <= j) {
        while (a[i] > temp && i <= j)i++, cnt++;
        while (a[j] <= temp && i <= j)j--;
        if (i < j) {
            swap(a[i], a[j]);
            cnt++;
        }
        i++, j--;
    }
    if (cnt >= k) {//若k<=cnt,就在左半段中递归寻找第k大
        return find_kth(l, l + cnt - 1, k);
    }
    else {//否则在就在右半段中递归寻找第k-cnt大的数
        return find_kth(l + cnt, r, k - cnt);
    }
}
int main() {
    int n; cin >> n;
    for (int i = 1; i <= n; i++)cin >> a[i];
    int k; cin >> k;
    cout << find_kth(1, n, k) << endl;
}