提示:以下是本篇文章正文内容
一、题目
给定一个长度为 n的整数数列,以及一个整数 k,
请用快速选择算法求出数列从小到大排序的第 k个数。
输入格式
第一行包含两个整数 n和 k。
第二行包含 n个整数(所有整数均在 1∼109 范围内),表示整数数列。
输出格式
输出一个整数,表示数列的第 k小数。
数据范围
1≤n≤100000,
1≤k≤n
输入样例:
5 3
2 4 1 5 3
输出样例:
3
二、思路及代码
1.思路
第一步:
主体使用的是快速排序的思路。
第二步:
变化的是选择,这里的函数q_check(l, r, k),
l 和 r:左右边界;
参数k :选取第 k 小的数。
第三步:
k 和 分界长度比较,sl 代表 左分支的长度,整个数组分界为
[l, j], [j + 1, r];
所以 sl = j - l + 1;
if k < sl:
q_check(l, j , k)
else :
q_check(j + 1, r, k - sl)
注: k - sl 代表着在右分支中选择第k - sl 小的数,因为左分支已经有 sl 个数了。
2.答案
代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int n, k;
int q[N];
int q_check(int l, int r, int k)
{
if(l == r) return q[l];
int x = q[l + r >> 1], i = l - 1, j = r + 1;
while(i < j)
{
while(q[++ i] < x);
while(q[-- j] > x);
if(i < j) swap(q[i], q[j]);
}
int sl = j - l + 1;
if(k <= sl) return q_check(l, j, k);
else return q_check(j + 1, r, k - sl);
}
int main()
{
cin >> n >> k;
for(int i = 0; i < n; i ++)
cin >> q[i];
cout << q_check(0, n - 1, k);
return 0;
}