satsuki26681534

博客园 首页 新随笔 联系 订阅 管理
  113 随笔 :: 0 文章 :: 4 评论 :: 51337 阅读

题目描述

如题所述,找到n个数中第K小的数字。
但是不同的是时间复杂度要求为O(n),也就是说基本上所有的排序算法都不能用了。
这里适合的算法是分治法,也就是使用快速排序。因为这道题的一个特点是只需要得到第k小的数字,而并没有说要对所有元素进行排序。如果我们把所有小于某个元素的元素都置于其左侧,且正好有k-1个这样的元素,那么这个元素自然地就是第k个元素。
image
代码如下:

#include<bits/stdc++.h>
using namespace std;
long long a[5000010];//一定要设全局变量 
//经过实验,不设全局变量而把数组作为参数传入函数也能AC,并不是一定要设全局变量。
inline int read(){	//快读 
	//比cin和cout使用的时间更短 
    char ch=getchar();
	int x=0,f=1;
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    } 
	while('0'<=ch&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    } return x*f;
}
int quicksort(int left,int right)
{
	//快速排序中选择的枢轴可以有很多种策略,这里是直接用a[left]作为枢轴
	//这个函数执行完成后,数组a中left-right的部分会以a[left]为界 
	int mid=a[left];//选取枢轴 
	while (left<right) 
	{
		while (left<right&&mid<=a[right])
			right--;
		a[left] = a[right];
		//从右往左循环查找小于枢轴的元素,如果发现就将其提到前面left处
		//不用担心,a[left]已经存储在变量mid里面了 
		while (left<right&&a[left]<=mid)
			left++;
		a[right] = a[left];
		//从左往右循环,发现比枢轴大的元素就放到后面去 
	}//退出循环时一定有left==right,而且左右两侧的元素分别小于和大于枢轴
	 
	a[left]=mid;
	return left;
	//返回枢轴在一轮排序后所在下标 
}
int find(int left, int right, int k)
{	
	//注意,这个函数的作用是在left到right的子数组中寻找整体数组中第k小的数字
	//这个k是目标在整体数组中的位置,而不是子数组中 
	int tem=quicksort(left,right);
	if(k==tem)
		printf("%d",a[k]);
		//这里是A[k]而不是A[tem]的原因是数组a是一直被修改的
		//所以当k == tem时,A[k]自然而然的就是第k小的元素 
	else if(k-1<tem)
		find(left,tem-1,k);
	else
		find(tem+1,right,k);
	return 0;//注意这里
}
int main()
{
	int n,k;
	n=read();
	k=read();
	for(int i=0;i<n;i++)
		a[i]=read();
	find(0,n-1,k);
	return 0;
}

注意!!

如果写的函数返回值类型不是void,就必须在函数里写上return语句,就算你并不需要任何返回值,否则就会产生runtimeerror。
另外,在某些时间复杂度要求苛刻的题目中,cin和cout是不能用的,需要用到快读函数来节省时间。

posted on   SaTsuki26681534  阅读(95)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示