专栏文章
题解:P1923 求第 k 小的数
P1923题解参与者 5已保存评论 7
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 5 条
- 当前快照
- 1 份
- 快照标识符
- @mioezkzf
- 此快照首次捕获于
- 2025/12/02 18:07 3 个月前
- 此快照最后确认于
- 2025/12/02 18:07 3 个月前
题解:P1923 【深基9.例4】求第 k 小的数
题目大意
一个大小为 的数组 ,输出数组中第 小的数(最小的数是第 小)。
分析
本题可以使用分治算法。分治,顾名思义就是“分而治之”,也就是把一个大问题分解成规模更小但本质相同的问题,再用同样的方法解决,再把小问题的解合并,就是大问题的解。
这一题,我们可以随便选择一个数,并将数组分为三部分:比它小的数,这个数本身,和比它大的数。然后再判断第 小的数位于哪个部分,再在这个部分中继续用同样的方法查找,直到得出答案为止。平均时间复杂度可以达到 。
注意最小的数是第 小,所以分治之前 要加一。且数据范围比较大,需要用
scanf 和 printf 快速读入输出。代码
可能这样说比较抽象,那就结合代码理解吧!
CPP#include <iostream>
#include <cstdio> // 快速读入输出头文件
#include <vector> // 动态数组头文件
using namespace std;
long long n, k; // 有自定义函数,使用全局变量
long long a[5000005];
void dfs(long long l, long long r) // 自定义函数
{
if (l > r) // 如果 l > r
{
return; // 直接返回
}
long long num = a[l];
// 随便选一个数,为了写代码方便就选第 1 个数
vector <long long> minn, maxn;
// 存储比这个数大或小的数的数组,因为大小未知,所以使用动态数组
for (long long i = l + 1; i <= r; ++i) // 遍历这一段区间
{
if (a[i] < num) // 将数字存入数组
{
minn.push_back(a[i]);
}
else
{
maxn.push_back(a[i]);
}
}
for (long long i = l; i < l + minn.size(); ++i)
{
a[i] = minn[i - l];
}
// 改变数组中数的位置,使得数组分为三部分:比 num 小的数,num 本身,和比 num 大的数
// 注意 for 循环的范围
a[l + minn.size()] = num;
for (long long i = l + minn.size() + 1; i <= r; ++i)
{
a[i] = maxn[i - l - minn.size() - 1];
}
if (k < minn.size() + 1) // 分类讨论,答案在左半边
{
dfs(l, l + minn.size() - 1); // 递归
}
else if (k == minn.size() + 1) // 答案正好是 num
{
printf("%lld", num); // 输出答案,注意使用 printf 更快
exit(0); // 直接退出程序
}
else // 答案在右半边
{
k -= minn.size() + 1; // 改变 k 的值
dfs(l + minn.size() + 1, r); // 递归
}
}
int main()
{
scanf("%lld %lld", &n, &k); // 输入,注意使用 scanf 更快
for (long long i = 1; i <= n; ++i)
{
scanf("%lld", &a[i]);
}
k += 1; // 题目说最小的数是第 0 小
dfs(1, n); // 搜索并递归
return 0; // 完结撒花!!!!!
}
这道题还可以直接用
sort 排序,或者用题面提到的 nth_element 函数,但本题的考点是分治算法,这里就不赘述其他方法了。你可以
点个赞再走吧!
注意
不要抄题解,会棕名的!
相关推荐
评论
共 7 条评论,欢迎与作者交流。
正在加载评论...