AcWing 786. 第k个数
1、题目(来源于AcWing):
给定一个长度为n的整数数列,以及一个整数k,请用快速选择算法求出数列的第k小的数是多少。
输入格式
第一行包含两个整数 n 和 k。
第二行包含 n 个整数(所有整数均在1~109范围内),表示整数数列。
输出格式
输出一个整数,表示数列的第k小数。
数据范围
1≤n≤100000,
1≤k≤n
输入样例:
5 3
2 4 1 5 3
输出样例:
3
2、基本思想:
用快速选择算法。当分界点x左边(有sl个数)全比它小右边(有sr个数)全比它大的时候,若k<=sl,则只需在x左边选择第k小的数,反之则在x右边选择第(k - sl)小的数。
3、步骤:
①找分界点x:q[l]、q[(l + r)/2]、q[r]都可以。
②将x左右两边排好,使得左边数都小于x,右边数都大于x。
③视情况选择递归x左边的还是递归x右边的。
4、C++代码如下(该代码引用AcWing网站的代码):
#include <iostream>
int quick_sort(int l, int r, int k);
using namespace std;
const int N = 1e5 + 10;
int n, k;
int q[N];
int main()
{
cin >> n >> k;
for (int i = 0; i<n; i++) cin >> q[i];
cout << quick_sort(0, n-1, k) << endl;
return 0;
}
int quick_sort(int l, int r, int k)
{
if (l == r) return q[l];//递归的终点就是l == r的时候
int x = q[(l + r)/2], 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;//上面的循环结束之后i == j,用i或是用j都一样
if (k <= sl) return quick_sort(l, j, k);//递归排左边
else return quick_sort(j + 1, r, k - sl);//递归排右边
}//该代码引用AcWing网站代码
注意事项:
用快速选择算法时间复杂度比用快排要低,故此处只挑选其中一边递归。