优先队列求第k小数

题目描述:

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

题目描述

有一个长度为n的数组,值为 a[i], 牛牛想找到数组中第 k 小的数。比如 1 2 2 3 4  6 中,第 3 小的数就是2.

牛牛觉得这个游戏太简单了,想加一点难度,现在牛牛有 m 个操作,每个操作有两种类型。

1 x  1 代表操作一,给数组中加一个元素 x 。(0 ≤ x ≤ 1e9)

2     2 代表操作二,查询第 k 小的数。如果没有 k 个数就输出−1

输入描述:

第一行有三个整数,n m k,(1≤n,m,k≤2e5)
第二行包含 n 个整数 a[i] ( 0 ≤ a[i] ≤ 1e9)
接下来m行,每行代表一个操作。具体见题目描述

输出描述:

每次查询输出一个第 k 小的数。

示例1

输入

5 4 3
1 2 3 4 5
2
1 1
1 3
2

输出

3
2

可以发现这是一个动态的过程,我们需要不断地执行插入数字和查询的操作。所以可以选择使用优先队列,插入时自动排序。

首先,我们得意识到一件事,如果选择用队列来做的话,我们是不能直接从队列中取出第k个元素的,能直接做到的就只是取出队首元素。另外,我们还发现,我们其实只关心那个第k个数,而其他的元素并没有那么重要,所以,我们可以在插入元素的过程中,就试图将第k个数放到队首去。

可以先将数组的元素用sort直接排序,然后依次放入优先队列,如果元素超过k个了,就弹出队首。比如,数组是1 3 2 4 5 7 6 8 9 ,k=5,排序后是1 2 3 4 5 6 7 8 9,先放进去1 2 3 4 5,优先队列内是5 4 3 2 1的顺序,然后进来6,数组元素超过5,弹出队首,应该就是6,然后再放入7 8 9,都依次被弹出,那么队首的元素5恰好就是原数组第5小的元素。如果再插入元素的话,如果大于5,就被弹出,第5小的还是5,如果小于5,5被弹出,答案就是一个更小的数,事实也确实如此。

上代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,m,k,d,s,x,cnt=0,mas[200010];
priority_queue<int,vector<int>,less<int>> q;

int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n>>m>>k;
	for(int i=1;i<=n;++i){
		cin>>mas[i];
	}
	sort(mas+1,mas+1+n);
	for(int i=1;i<=n;++i){
		q.push(mas[i]);
		if(q.size()>k) q.pop();
	}
	for(int i=1;i<=m;++i){
		cin>>d;
		if(d==1){
			cin>>s;
			q.push(s);
		    if(q.size()>k) q.pop();
		} 
		else if(d==2){
			if(q.size()<k) cout<<-1<<endl;
			else{
				cout<<q.top()<<endl;
			}
		}
	}
	return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值