Acwing.786.第k个数

153 阅读1分钟

www.acwing.com/problem/con… 本题的主要思路是利用快排中的分区概念来解决。对于数组arr,我们会在数组中选择一个元素作为pivot,然后进行原地分区,arr[0...p-1],arr[p],arr[p+1...n]。

如果p + 1 = k,那就是我们需要的答案;如果k > p + 1,说明第k大元素出现在arr[p+1...n-1]区间,就继续按照上面的思路递归地在arr[p+1...n-1]这个区间内查找。同理,如果k < p + 1,那就在arr[0...p-1]内找。

#include <iostream>
using namespace std;

const int N = 100010;
int arr[N];

int n, k;

int quick_select(int arr[], int start, int end, int k) {
    if(start >= end) return arr[start];
    
    int x = arr[start + ((end - start) >> 1)], i = start - 1, j = end + 1;
    while(i < j) {
        do ++i; while(arr[i] < x);
        do --j; while(arr[j] > x);
        if(i < j) swap(arr[i], arr[j]);
    }
    
    int len = j - start + 1;
    if(len >= k) return quick_select(arr, start, j, k);
    
    return quick_select(arr, j + 1, end, k - len);
}
 
int main() {
    cin >> n >> k;
    for(int i = 0; i < n; ++i)
        scanf("%d", &arr[i]);
    
    cout << quick_select(arr, 0, n - 1, k) << endl;
    return 0;
}

这道题的时间复杂度是O(n)的,第一次分区查找,需要对遍历n个元素。第二次分区查找,需要遍历n/2个元素,依次类推,直到区间缩小到1。

n+n2+n4+n8++1=12log2n+112=2n1n + \frac{n}{2} + \frac{n}{4} + \frac{n}{8} + \ldots + 1 = \frac{1 - 2^{log_2^n+1}}{1-2} = 2n - 1
an=a1qn1,an=n,a1=1,q=2,所以,n=log2n+1a_n = a_1 * q^{n-1}, a_n = n, a_1 = 1, q = 2,所以, n = log_2^n + 1

参考 王争 《数据结构与算法之美》