牛牛找工作这个题目是2019年网易校招编程真题。本人菜鸟,解这个题解了一天,没有成果,也不知道哪里出了错。后来干脆去找已经成功提交的代码。对着别人的代码一行一行码。然后自己简单修改一下。现在回顾反思一下解题思路。
题目描述
为了找到自己满意的工作,牛牛收集了每种工作的难度和报酬。牛牛选工作的标准是在难度不超过自身能力值的情况下,牛牛选择报酬最高的工作。在牛牛选定了自己的工作后,牛牛的小伙伴们来找牛牛帮忙选工作,牛牛依然使用自己的标准来帮助小伙伴们。牛牛的小伙伴太多了,于是他只好把这个任务交给了你。
输入描述:
每个输入包含一个测试用例。 每个测试用例的第一行包含两个正整数,分别表示工作的数量N(N<=100000)和小伙伴的数量M(M<=100000)。 接下来的N行每行包含两个正整数,分别表示该项工作的难度Di(Di<=1000000000)和报酬Pi(Pi<=1000000000)。 接下来的一行包含M个正整数,分别表示M个小伙伴的能力值Ai(Ai<=1000000000)。 保证不存在两项工作的报酬相同。
输出描述:
对于每个小伙伴,在单独的一行输出一个正整数表示他能得到的最高报酬。一个工作可以被多个人选择。
示例1
输入
3 3
1 100
10 1000
1000000000 1001
9 10 1000000000
输出
100
1000
1001
本题的解题思路分为5步:
1. 按格式读取工作数据和需要找工作的人员数量;
2.对工作数据按照难度进行排序;
3.重新分配每个工作难度对应的薪水;
4.读取员工的能力,并找到适合其能力的最高薪水;
5.输出每个员工的最高薪水。
接下来我一步一步地对每一步的细节进行解释说明。
1. 按格式读取工作数据和需要找工作的人员数量;
先看输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数,分别表示工作的数量N(N<=100000)和小伙伴的数量M(M<=100000)。
接下来的N行每行包含两个正整数,分别表示该项工作的难度Di(Di<=1000000000)和报酬Pi(Pi<=1000000000)。
第一行数据有两个正整数,分别为工作种类N和找工作的人数M。根据M和N的大小条件限制。可以用int (32位机器上可以表示的数据范围为2^-31~(2^31-1))型的数据表示。有了工作的数量N,就可以将工作数据读取到内存中。这里数据形式使用了结构体,工作结构体包含了两个成员,第一个成员是difficulty表示工作难度,第二个成员salary表示薪水数量。二者都采用整型定义。在这里使用了malloc函数开辟了可以容纳工作数据的一个地址空间。这个空间里用于存放工作数据结构体。首地址交给了joblist结构体指针变量。然后以此按照给定格式将工作数据存到结构体数组中去。这种使用malloc开辟空间的做法减少了空间浪费,需要多少,开辟多少。
2.对工作数据按照难度进行排序
拿到了工作数据之后,为了方便后来的比较。按照难度,将工作数据排个序。容易的在低地址,难的在高地址。这里顺序的升序降序无所谓,只是代码表示的不同。本文使用了从低到高的排序方法。这里使用了qsort库函数。
qsort函数有四个参数:1.排序后存放数据的首地址,一般放一个数组的首地址;2.需要排序元素的数量,对数组中所有的元素排序,放上数组元素的数量即可;3.被排序的各个元素所占用的字节大小;4 指向函数的指针,用于确定排序的顺序(需要用户自定义一个比较函数)这个函数的类型和形参是固定的。函数体可以根据需要自定义。
int comp(const void *a,const void *b)
{
job *a1=(job *)a,*a2=(job *)b;
if(a1->difficulty>a2->difficulty)
return 1;
else if(a1->difficulty==a2->difficulty)
return 0;
else
return -1;
}
本例定义如上,输入参数作为工作数据的结构体指针。比较两个结构体指针指向的结构体中difficulty即工作难度的大小。当a1所指向的结构体成员difficulty大于a2所指向的结构体成员difficulty时,返回1;两者相等时,返回0;a1所指向的结构体成员difficulty小于a2所指向的结构体成员difficulty时,返回-1。这是升序排列。反之,则为降序排列。
3.重新分配每个工作难度对应的薪水;
这个思路是这样的。输入的工作数据中,有可能出现工作难度很大,但是薪水比较低的情况。这种工作往往不是最好的工作。所以,需要将工作难度和薪水相匹配。如果工作A的工作难度大于工作B的难度,那么工作A的薪水也应当大于等于工作B。由于排序中,工作难度是递增的,所以,薪水是不减的。工作难度和薪水相匹配之后,有利于依据工作能力来寻找最高的薪水。
4.读取员工的能力,并找到适合其能力的最高薪水;
这是关键的一步。这里的思路决定了整个程序的时间复杂度。这里使用了二分法。
每获取一个人的能力水平之后。首先定义起点位置start=0和终点位置end=N。计算出中间点mid=(start+end)/2的难度水平。此时有三种情况,可以分别处理。
(1).此人的能力恰好能胜任mid这一位置的难度,不能胜任下一位置的难度。由于薪水是不减的,所以,此人能力范围能所能获得的最高薪水为mid位置的薪水。跳出此次寻找。输出其最高薪水。进行下一个人的寻找阶段。
(2).此人能力小于中间点mid位置的工作难度。此时起点不变,将mid-1作为终点。更新mid。
(3).此人能力大于中间点mid位置的工作难度。此时终点不变,将mid+1作为起点。更新mid。
当起点位置大于终点位置的时候,此人的能力值不等于任何一个工作的难度。介于mid左右两个工作难度之间。跳出此次寻找。
5.输出每个员工的最高薪水。
每一次寻找结束时。有两种情况结束寻找(1).此人的能力等于mid位置的工作难度;(2)。此人的能力在mid-1到mid+1两个工作的难度之间。所以,对其能力与mid位置的工作难度比较之后,即可判断此人所能获得的最大薪水是mid位置的薪水还是mid-1位置的薪水。
完整源码如下:
#include <stdio.h>
#include <stdlib.h>
int comp(const void* _a , const void* _b);
typedef struct _job
{
int difficulty;
int salary;
}job;
int main() {
int N,M,start=0,end,mid;//N种工作,M个员工
int temp=0;
/****************读取工作数据****************/
scanf("%d %d",&N,&M);
job *joblist=(job*)malloc(sizeof(job)*N);
for ( int i = 0; i < N; ++i) {
scanf("%d %d",&joblist[i].difficulty,&joblist[i].salary);
}
/******按照工作难度排序,从容易到复杂********/
qsort(joblist,N,sizeof( job ),comp);
/*****对每个工作难度对应的薪水重新分配*******/
temp=joblist[0].salary;
for (int i = 1; i < N; ++i) {
if (joblist[i].salary<temp)
{
joblist[i].salary=temp;
} else
{
temp=joblist[i].salary;
}
}
/*****读取员工的能力并找到适合其能力的最高薪水*****/
for (int j = 0; j < M; ++j)
{
scanf("%d",&temp);
for (start=0,end=N-1; start <=end; ) {
mid=(start+end)/2;
if((temp==joblist[mid].difficulty)&&(temp<joblist[mid+1].difficulty))
{
break;
} else if (temp<joblist[mid].difficulty)
{
end=mid-1;
} else
{
start=mid+1;
}
}
/***输出每个员工的最高薪水********/
if (temp>=joblist[mid].difficulty)
{
printf("%d\n",joblist[mid].salary);
} else
{
printf("%d\n",joblist[mid-1].salary);
}
}
return 0;
}
int comp(const void *a,const void *b)
{
job *a1=(job *)a,*a2=(job *)b;
if(a1->difficulty>a2->difficulty)
return 1;
else if(a1->difficulty==a2->difficulty)
return 0;
else
return -1;
}