DreamJudge-1383-查找第K小的数
1.题目描述
?Time Limit: 1000 ms
Memory Limit: 256 mb
查找一个数组的第K小的数,注意同样大小算一样大。 如 2 1 3 4 5 2 第三小数为3。
输入输出格式
输入描述:
输入有多组数据。
每组输入n,然后输入n个整数(1<=n<=1000),再输入k。
输出描述:
输出第k小的整数。
输入输出样例
输入样例#:
6
2 1 3 5 2 2
3
输出样例#:
3
题目来源
北京邮电大学
2.题解
注意这一题不同于【深基9.例4】求第 k 小的数, 因为题目要求查找一个数组的第K小的数,注意同样大小算一样大
2.1 set集合去重 + nth_element寻找第k小的数
思路
这里因为nth_element会将重复的数也纳入计算,所以先要进行去重
这里使用set去重后,nth_element要求连续数组,所以还要将set转化为vector数组
代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
int main() {
int n;
while (cin >> n) {
// 注意这里nth_element将重复的数每个都进行了计数,与题目要求的只看成一个不符,所以这里进行去重
set<int> unique_numbers;
for (int i = 0; i < n; ++i) {
int number;
cin >> number;
unique_numbers.insert(number);
}
int k;
cin >> k;
// 将set转换为vector
vector<int> numbers(unique_numbers.begin(), unique_numbers.end());
// 使用 nth_element(只能使用连续的vector数组) 进行部分排序!!!
nth_element(numbers.begin(), numbers.begin() + k - 1, numbers.end());
// 输出第 k 小的元素
cout << numbers[k - 1] << endl;
}
return 0;
}
2.2 sort排序 + unique(形式去重,只是将重复元素全部放到数组末尾了)
思路
先排好,再去重,然后直接定位第k位即可!
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, k, a[100];
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n); // 先排好
unique(a+1,a+1+n); // 再去重
cin>>k;
cout<<a[k]<<endl;
return 0;
}
2.3 分治算法-实现nth_element
思路
参考【深基9.例4】求第 k 小的数
这里因为实际上要进行去重,所以这样做反而画蛇添足了,纯作为了解一下把!
代码
#include<bits/stdc++.h>
using namespace std;
int k, ans;
//这里arr必须设置为全局变量,不然每次都作为函数输入参数,会消耗大量资源和时间爱你
vector<int> arr;
// 这里由于cin读入过慢,而这里n( 1≤<5000000且n为奇数),所以使用快读缩短读取时间爱
inline int read(){ //快读
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;
}
void sortNum(int begin, int end){
// 递归终止条件
if(begin == end){
ans = arr[begin];
return;
}
// 初始化
int l = begin, r = end;
// 确定一个基准判断点, 只固定值,不固定位置!!!
int currNum = arr[(end - begin) / 2 + begin];
while(l <= r){
//由于我取的currNum是中位数,所以l第一次最多停留在中位数,r同理
//由于后面if中的交换,l指针左边的左半区间必都是小于等于currNum的值,r指针右边的右半区间必是大于等于currNum的值,都是一种"有序"状态
while(arr[l] < currNum) l++; //l指向第一个不小于currNum的值
while(arr[r] > currNum) r--; //r指向第一个不大于currNum的值
if(l <= r){
swap(arr[l++], arr[r--]); // 自己不需要的数正是对方需要的
}
}
// k ——我们要取的第k小的数,此时必然有 l > r
// 但是最终由于最后一次的l++,r--; l指向第一个大于等于currNum的值,r指向第一个小于等于currNum的值,故为 sortNum(l, end)和 sortNum(begin, r)
if(k >= l) sortNum(l, end); // 表明在右区间
else if(k <= r) sortNum(begin, r); //表明在左区间
//这种情况就是(r<k<l), 如果现在已经有 l = r, l++, r--,说明此时是arr[l] = arr[r] = currNum; 就有可能 r + 1 = k = l - 1;
else {
sortNum(r+1 , l-1);
}
}
int main(){
int n;
n = read();
arr.resize(n);
set<int> st;
for(int i = 0; i < n; i++){
int num = read();
st.emplace(num);
}
k = read() + 1;
arr.assign(st.begin(), st.end());
sortNum(0, n - 1);
cout << ans;
return 0;
}
2.3 大根堆
思路
由于建堆和更新堆时间复杂度都是O(n),我们考虑使用大根堆
思路很简单,我们总是维护一个大小为k+1(这里k从0开始,其实是下标,真正个数为k+1!!!)的大根堆,遍历数组的同时不断更新堆,保证大根堆中是当前遍历到的元素中最小的k+1个
而因为是大根堆,所以根节点值是这k+1个元素中最大的,也就是说,在遍历完数组所有元素后,小根堆的根节点值就是我们要求的第K大的元素值!
代码
#include<bits/stdc++.h>
using namespace std;
vector<int> heap;
// 这里由于cin读入过慢,而这里n( 1≤<5000000且n为奇数),所以使用快读缩短读取时间
inline int read(){ //快读
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;
}
void heapAdjust(int curIndex, int len){
int child = curIndex * 2 + 1;
int curValue = heap[curIndex];
while(child < len){
// 判断左右节点的选择
if(child + 1 < len && heap[child] < heap[child + 1]){
child++;
}
if(curValue < heap[child]){
heap[curIndex] = heap[child];
curIndex = child;
child = curIndex * 2 + 1;
}else{
break;
}
}
// 更新当前Index对应的value值(前面更新的都是child换上去的值,最后一个被换过来的需要单独处理)
heap[curIndex] = curValue;
}
int main(){
int n, k;
n = read();
k = read();
vector<int> nums(n);
for(int i = 0; i < n; i++){
nums[i] = read();
}
heap.assign(nums.begin(), nums.begin() + k + 1);
int sublen = heap.size(), len = n;
for(int i = sublen / 2 - 1; i >= 0; i--){
heapAdjust(i, sublen);
}
for(int j = k + 1; j < len; j++){
if(nums[j] < heap[0]){
heap[0] = nums[j];
heapAdjust(0, sublen);
}
}
cout << heap[0];
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了