每日一题-牛牛找工作

题目描述

本题来自牛客网,为网易2019年校招题之一。(点我跳转)

题目描述
为了找到自己满意的工作,牛牛收集了每种工作的难度和报酬。牛牛选工作的标准是在难度不超过自身能力值的情况下,牛牛选择报酬最高的工作。在牛牛选定了自己的工作后,牛牛的小伙伴们来找牛牛帮忙选工作,牛牛依然使用自己的标准来帮助小伙伴们。牛牛的小伙伴太多了,于是他只好把这个任务交给了你。
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数,分别表示工作的数量N(N<=100000)和小伙伴的数量M(M<=100000)。
接下来的N行每行包含两个正整数,分别表示该项工作的难度Di(Di<=1000000000)和报酬Pi(Pi<=1000000000)。
接下来的一行包含M个正整数,分别表示M个小伙伴的能力值Ai(Ai<=1000000000)。
保证不存在两项工作的报酬相同。
输出描述:
对于每个小伙伴,在单独的一行输出一个正整数表示他能得到的最高报酬。一个工作可以被多个人选择。
时间限制:2秒 空间限制:65536K

题目分析

我们可以看到,这道题并不难,可以暴力破解,时间复杂度为O(n*m)。但是由于其数据量过大,有超时的风险。因此我们必须优化其时间复杂度,将其降低到O(mlogn),甚至是O(n+m)。

解决方案

首先,给出下文的符号及其释义。

符号释义
n工作的数量
m小伙伴的数量
di[i]第i个工作的难度
pi[i]第i个工作的报酬
ai[i]第i个小伙伴的能力
pay[i]第i个小伙伴的最高报酬

下面给出的是暴力破解的核心代码。

int ai,pay;
for(int i=0;i<m;++i)
{
	cin>>ai;
	pay=0;
	for(int j=0;j<n;j++)
	{
		if(ai>=di[j]&&pay>pi[j])
			pay=pi[j];
	}
	cout<<pay<<'\n';
}

分析以上代码可以得知,暴力破解的时间复杂度过高是由于需要在混乱的数组中查找符合能力要求且工资最高的的工作。所以,优化其查找算法可以有效降低其时间复杂度。
自然而然,我们可以先剔除报酬与难度不匹配的工作(即剔除有其他工作难度低于其难度,但报酬不低于其报酬的工作)。然后,可以用快排将di[]和pi[]以di为key排序,然后查找时使用二分查找即可。此时的时间复杂度为max(O(nlogn),O(mlongn))。其中,nlogn为将di与pi快排的时间复杂度。mlogn为给m个小伙伴用快排寻找最高工作报酬的时间复杂度
下面给出核心代码

priority_queue<map> work;
...
clear(work);
for(int i=0;i<m;++i)
{
	pay=bisearch(work,ai[i]);
}

既然能将di与pi排序,那么我们可以考虑是否能将ai排序呢?
答案是肯定的的。将ai与i绑定,以免混淆小伙伴,然后以ai为key快排即可。输出时,可以依次将其队首比较即可。下面给出核心代码。

priority_queue<map> human;
...
while(!human.empty())
{
	...
	if(work.empty())
	{
		while(!human.empty())
        {
        	pay[human.top()->value]=0;
        	human.pop();
       	}
       	break;
	}
	if(human.top()->key>=work.top()->key)
	{
		pay[human.top()->value]=work.top()->value;
		human.pop();
	}
	else
	{
		while(work.top()->key>human.top()->key&&!work.empty())
        {
        	work.pop();
		}
	}
	
}

此时,时间复杂度为max(O(nlogn),O(mlogm),O(n+m))。


2019/9/15 补充:
或许有人要问,将小伙伴排序,时间复杂度没有优化,那么这有什么用?实际上,若用空间换时间的策略的话,可以用计数排序代替快排。计数排序的时间复杂度为O(n),那么时间复杂度会被降为O(n+m)。

明天的题

题目描述
小Q得到一个神奇的数列: 1, 12, 123,…12345678910,1234567891011…。
并且小Q对于能否被3整除这个性质很感兴趣。
小Q现在希望你能帮他计算一下从数列的第l个到第r个(包含端点)有多少个数可以被3整除。

若有更好的想法,欢迎讨论区见。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值