1.【力扣刷题】合并两个有序链表2.【力扣】旋转链表3.【力扣】删除链表中的结点4.【力扣】反转链表II5.【力扣】分隔链表6.【力扣】删除排序链表中的重复元素II7.【洛谷】奖学金(结构体排序)8.【洛谷】明明的随机数(双指针去除重复元素)
9.【洛谷】求第k小的数字(分治算法)
10.【洛谷】阶乘之和(高精度运算)11.【洛谷】闰年12.【洛谷】数的性质13.【洛谷】虫子吃苹果14.【力扣】奇偶链表15.【力扣】不同路径II(动态规划)16.【力扣】数楼梯(动态规划)(看来高精度不学不行了)17.【力扣】斐波那契数列(动态规划入门)18.【力扣】最大子数组和(贪心)19.【力扣】摆动序列(贪心)20.【力扣】排列问题(回溯法)(去重)21.【力扣】排列问题(回溯法)(memset函数初始化数组)22.【力扣】非递减子序列23.【力扣】子集II(回溯法)(排序函数的一种隐藏用法?)24.【力扣】复原IP地址(回溯法)(分割问题)25.【力扣】分割回文串(回溯法)26.【力扣】组合总和3(组合的去重)27.【力扣】组合总数(回溯法)28.【力扣】电话号码的组合(回溯法)29.【力扣】求组合(回溯算法)30.【力扣】括号匹配(栈的应用)31.【力扣】组合总数(另一种整数溢出)32.【CUMTOJ】法师康工人(代码细节控制)33.【代码随想录】零钱兑换34.【代码随想录】零钱兑换II(关于组合与排列的区别)35.【代码随想录】完全背包36.【力扣】岛屿数量(体会一下dfs和bfs思路的实质)37.【代码随想录】广度优先搜索38.【代码随想录】深度优先搜索39.【力扣】重新安排行程(很难的回溯题)(未完待续)40.【力扣】零和一(不是多重背包)41.【力扣】最长公共子序列(动态规划)(还是得学套路才能会做)42.【力扣】目标和(新鲜的01背包题)43.【力扣】分割等和子集(不太像01背包的01背包)44.【力扣】加油站(读题)题目描述
如题所述,找到n个数中第K小的数字。
但是不同的是时间复杂度要求为O(n),也就是说基本上所有的排序算法都不能用了。
这里适合的算法是分治法,也就是使用快速排序。因为这道题的一个特点是只需要得到第k小的数字,而并没有说要对所有元素进行排序。如果我们把所有小于某个元素的元素都置于其左侧,且正好有k-1个这样的元素,那么这个元素自然地就是第k个元素。
代码如下:
#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是不能用的,需要用到快读函数来节省时间。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理