第k个数

1.问题描述

一个题目是这样的,先给一行整数数列,求数列从小到大排列之后的第 k 个数。
暴力解法就是先排好序,然后输出第 k 个数。
但是如果给定的数列太大,排序的过程就会浪费很多的时间,我们可以通过快速排序的性质,使其在未完全排好序的过程中就可以找到第 k 个数。
点击查看快速排序讲解

2.解题思路

首先在快速排序的过程中,我们是将数列每次都分成两个部分进行排序,如果我们设法得知了第 k 个数所在的部分,那么另外一个部分,我们就可以不需要进行排序了。

现在我们的问题就是如何得知第 k 个数所在的部分是哪一个。在快速排序分好两个部分之后,我们可以得知,第一个部分为 [l, j],第二个部分为 [j + 1, r]。我们还可以知道第一个部分是小于第二个部分的,那么 第一个部分里的整数就是 第1个数,第2个数,......,第j - l + 1个数,如果 k <= j - l + 1 那么就说明 k 在第一个部分里,否则就是在第二个部分里。此时我们所求的数在第二个部分里就是 第 k - (j - l + 1)个数

3.代码实现

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const int N = 100, INF = 1e9;
int arr[N], n, k;

int quick_sort(int* a, int l, int r, int kt){
    if (l >= r) return a[l];
    int i = l - 1, j = r + 1, mid = a[l + r >> 1];
    while (i < j){
        do i ++; while (a[i] < mid);
        do j --; while (a[j] > mid);
        if (i < j) swap(a[i], a[j]);
    }
    int x = j - l + 1; //算出第一个部分中包含的整数个数
    if (kt <= x) return quick_sort(a, l, j, kt);
    else return quick_sort(a, j + 1, r, kt - x); // 注意此处kt需要减去x的值,因为前x的数在第一个部分中
}

void solve(){
    cin >> n >> k;
    for (int i = 1; i <= n; i++){
        cin >> arr[i];
    }
    cout << quick_sort(arr, 1, n, k) << "\n";
}

int main(){
    int tt = 1;
	// cin >> tt;
	while (tt--){
        solve();
    }
    return 0;
}
posted @ 2024-03-01 22:19  ora12321  阅读(21)  评论(0编辑  收藏  举报