第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;
}