首页 > 编程语言 >【洛谷】求第k小的数字(分治算法)

【洛谷】求第k小的数字(分治算法)

时间:2024-03-05 21:13:24浏览次数:40  
标签:分治 ch 洛谷 函数 元素 算法 全局变量

题目描述

如题所述,找到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是不能用的,需要用到快读函数来节省时间。

标签:分治,ch,洛谷,函数,元素,算法,全局变量
From: https://www.cnblogs.com/satsuki26681534/p/18054115

相关文章

  • 3月5日-java随笔(雪花算法)
    一、简单介绍一下雪花算法原理1、雪花算法生成一个64bit的长整型标识符,其内部结构包含四个部分。首先,最左侧的一个bit通常被置为0作为符号位(在实际应用中往往无意义)。接下来的41bit用于存储自某个时间起点以来的毫秒级时间戳,以此确保生成的ID具有时间上的有序性。第三个组成部分......
  • 代码随想录算法训练营第三十六天| ● 738.单调递增的数字 ● 968.监控二叉树 ● 总
    单调递增的数字 题目链接:738.单调递增的数字-力扣(LeetCode)思路:从左向右验证是否按位单调递增,如果出现递减的区间,则从该位开始验证该位减1后是否比左边的相邻位大,如果不符合就接着向左寻找这样的位,如果找到了,则将该位前面的位复制到结果中,该位减1加入结果,该位之后的位全部改......
  • day56 动态规划part13 代码随想录算法训练营 718. 最长重复子数组
    题目:718.最长重复子数组我的感悟:有难度,不好想。理解难点:二维DP,记住那个图:===============听课笔记:我的代码:classSolution:deffindLength(self,nums1:List[int],nums2:List[int])->int:#初始化#假设内层是nums1,n,j,外层是nums2,m,......
  • 洛谷题单指南-搜索-P2895 [USACO08FEB] Meteor Shower S
    原题链接:https://www.luogu.com.cn/problem/P2895题意解读:所谓安全格子,就是在所有流星坠落之后,没有被烧焦的格子,要计算从起点到这些格子任一一个的最短路径,BFS可以解决。解题思路:1、读取数据,先把所有流星坠落点以及周围被烧焦的格子进行标记,得到安全格子2、从起点开始BFS,每走......
  • 文心一言 VS 讯飞星火 VS chatgpt (208)-- 算法导论15.4 5题
    五、设计一个O($n^2$)时间的算法,求一个n个数的序列的最长单调递增子序列。要写代码的时候,请用go语言。文心一言,抛panic:在Go语言中设计一个O(n^2)时间复杂度的算法来求一个n个数的序列的最长单调递增子序列(LongestIncreasingSubsequence,LIS)可以使用动态规划的方法......
  • day56 动态规划part13 代码随想录算法训练营 674. 最长连续递增序列
    题目:674.最长连续递增序列我的感悟:网速快是不一样!!这个题别看简单,写不出递推公式也白搭理解难点:递推公式,是只跟昨天的比,如果没有,就重新计算!听课笔记:我的代码:classSolution:deffindLengthOfLCIS(self,nums:List[int])->int:dp=[1]*len(nums)......
  • 动手学强化学习(七.1):DQN 算法代码
    一、代码如下:importrandomimportgymimportnumpyasnpimportcollectionsfromtqdmimporttqdmimporttorchimporttorch.nn.functionalasFimportmatplotlib.pyplotaspltimportrl_utilsclassReplayBuffer:'''经验回放池'''......
  • 代码随想录算法训练营第三十六天 | 56. 合并区间,763.划分字母区间,435. 无重叠区间
    435.无重叠区间 已解答中等 相关标签相关企业 给定一个区间的集合 intervals ,其中 intervals[i]=[starti,endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。 示例1:输入:intervals=[[1,2],[2,3],[3,4],[1,3]]输出:1解......
  • day56 动态规划part13 代码随想录算法训练营 300. 最长递增子序列
    题目:300.最长递增子序列我的感悟:之前做过,都忘记了,这次好好记思路理解难点:dp[i]是由昨天的历史遍历后,得到今天的值 听课笔记:我的代码:classSolution:deflengthOfLIS(self,nums:List[int])->int:#难点是dp的推导公式,#dp[i]是截止到n......
  • 查找/排序算法
    //二分查找publicstaticbooleanBinarySearch(inttarget,int[]array){intleft=0;intright=array.length-1;while(left<=right){intmiddle=(left+right)/2;//中间位置if(array[middle]<target)......