求第 k 小的数
题目描述
输入 n n n( 1 ≤ n < 5000000 1 \le n < 5000000 1≤n<5000000 且 n n n 为奇数)个数字 a i a_i ai( 1 ≤ a i < 10 9 1 \le a_i < {10}^9 1≤ai<109),输出这些数字的第 k k k 小的数。最小的数是第 0 0 0 小。
请尽量不要使用 nth_element
来写本题,因为本题的重点在于练习分治算法。
输入格式
输出格式
输入输出样例
输入 #1
5 1
4 3 2 1 5
输出 #1
2
1.题意解析
这道题建议不要直接用sort
做。因为本题的重点在于练习分治算法。
我们可以根据快速排序思想来寻找第k小的数,但是并不要把整个序列排序后再输出。
我们可以从最开始的序列开始,逐步逼近第 k k k个位置。详细讲解见注释(建议自己画图理解一下,或者看一下我的那篇将快速排序的文章)。
2.AC代码
#include<bits/stdc++.h>
using namespace std;
int ans,n,a[5000010],k,i;
void find_kth(int arr[],int kth,int left,int right)
{
if(left==right)//记录答案
{
ans=arr[left];
return;
}
int i=left,j=right,tmp=arr[(left+right)/2];//将中间的数作为基准数
do
{
while(arr[i]<tmp)//从左向右找
i++;
while(arr[j]>tmp)//从右向左找
j--;
if(i<=j)
{
int t=arr[i];
arr[i]=arr[j];
arr[j]=t;
i++;j--;//i和j这两个位置不用再排查了
}
}while(i<=j);//循环结束i总是比j大且相差2
if(kth<=j)//答案在左区间
find_kth(arr,kth,left,j);
else if(i<=kth)//答案在右区间
find_kth(arr,kth,i,right);
else find_kth(arr,kth,j+1,i-1);//左右区间都不在,找到答案了
}
int main()
{
scanf("%d%d",&n,&k);//不用scanf没法过
for(i=0;i<n;i++)
scanf("%d",&a[i]);
find_kth(a,k,0,n-1);//调用寻找第k个数
printf("%d",ans);
return 0;
}
3.扩展
3.1.sort函数
由于数据太水了 sort
优秀的时间复杂度(
O
(
n
log
n
)
O(n\log n)
O(nlogn)),所以
99
%
99\%
99%的排序题都能用sort
做。这里也是直接给出代码。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,a[5000010],k,i;
scanf("%d%d",&n,&k);//不用scanf没法过
for(i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
printf("%d",a[k]);
return 0;
}
3.2.nth_element函数
这里再介绍一个非常好用的函数——nth_element
。它也是STL里分装的函数。调用后返回数组中第
k
k
k小的数,但是不保证数组有序。其基本语法如下:
nth_element(数组名+起始下标,数组名+k,数组名+终止下标+1);
具体使用如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,a[5000010],k,i;
scanf("%d%d",&n,&k);//不用scanf没法过
for(i=0;i<n;i++)
scanf("%d",&a[i]);
nth_element(a,a+k,a+n);//用nth_element做
printf("%d",a[k]);
return 0;
}
喜欢就订阅此专辑吧!
【蓝胖子编程教育简介】
蓝胖子编程教育,是一家面向青少年的编程教育平台。平台为全国青少年提供最专业的编程教育服务,包括提供最新最详细的编程相关资讯、最专业的竞赛指导、最合理的课程规划等。本平台利用趣味性和互动性强的教学方式,旨在激发孩子们对编程的兴趣,培养他们的逻辑思维能力和创造力,让孩子们在轻松愉快的氛围中掌握编程知识,为未来科技人才的培养奠定坚实基础。
欢迎扫码关注蓝胖子编程教育