网易笔试|网易笔试到底有多难

网易笔试(网易笔试到底有多难)网易笔试|网易笔试到底有多难



作者:帅地
来源:苦逼的码农
今天我要将的这道题是网易 8 月 3 号研发岗笔试的第一题,也是四道题中最简单的一道 。这道题涉及到前缀和的应用,所以我想借这道题给大家讲一讲前缀和相关的一些知识,以后大家遇到这道题,就可以快速秒杀了 。
问题描述
下面我描述下这道题,不过我给的描述是简化版的,实际上再做笔试题的时候,每道题的描述都巨长,一般都会根据实际场景来给出问题的,有些人可能阅读了十几分钟,然后不知道自己要干嘛,我这里给出最简化的版本 。

有一个班级有 n 个人,给出 n 个元素,第 i 个元素代表 第 i 位同学的考试成绩,接下来进行 m 次询问,每次询问给出一个数值 t,表示第 t 个同学,然后需要我们输出第 t 个同学的成绩超过班级百分之几的人,百分数 p 可以这样算:p = 百思特网(不超过第 t 个同学分数的人数 ) / n * 100% 。输出的时候保留到小数点后 6 位,并且需要四舍五入 。输入描述:第一行输入两个数 n 和 m,两个数以空格隔开,表示 n 个同学和 m 次询问 。第二行输入 n 个数值 ni,表示每个同学的分数,第三行输入 m 个数值mi,表示每次询问是询问第几个同学 。(注意,这里 2<=n,m<=100000,0<=ni<=150,1<=mi<=n)输出描述:输出 m 行,每一行输出一个百分数 p,代表超过班级百分之几的人 。示例1:输入 :3 250 60 701 2输出33.333333%66.666667%
第一题大致是这样,不过不是和原题完全一样哈,在输入和输出有小许区别,因为具体的输入输出我忘了 。我这个描述说简化好像也挺长,不过原题就更加长了 。
解答
那么这道题难吗?说实话不难,不过你可以先自己再脑子里想想怎么做比较好,或许在考场上 20 分钟你还真不一定做的出来 。
有些人说,这还不简单,每次询问的时候,我都遍历一下所有人的成绩,这样的花时间复杂度是 O(n * m),显然,如果你这样做,那么是一定通不过的,一定会超时 。一般暴力法能够通过 20% ~ 30% 的测试用力,如果一道题 20 分的话,能拿到 4~6 分 。如果你实在没思路,那么暴力也是个不错的选择 。
1、二分法
这道题我是用二分法做的,就是先对所有人的成绩进行排序,不过排序的时候我们需要开一个新的数组来存储 。然后每次查询的时候可以通过二分查找进行匹配,由于用到了排序,需要百思特网花 O(nlogn) 的时间,m 次查询花的时间大致为 O(mlogn) 。所以平均时间复杂度可以算是 O((m+n)logn) 。这个时间复杂度通过所有测试用例,代码如下(没学过java的也能看懂):
public class Main { // 主函数,相当于c语言的main方法 public static void main(String[] args){ Scanner in = new Scanner(System.in); int m = in.nextInt(); int n = in.nextInt(); // 存放成绩的数组 int[] a = new int[n]; // 存放排序过后的成绩 int[] b = new int[n]; // 输入 n 个人的成绩 for(int i = 0; i < n; i++){ a[i] = in.nextInt(); b[i] = a[i]; } // 排序 Arrays.sort(b); // 进行查询 for(int j = 0; j < m; j++){ // 输入是要查询第几个同学 int t = in.nextInt(); // 把这个同学的分数拿出来 int fen = a[t - 1]; // 通过二分查找是排在第几位 int sum = binarySearch(b, fen) - 1; double t = sum * 1.0 / n * 100; System.out.printf("%.6f\n", t); } } private static int binarySearch(int[] b, int fen){ int l = 0; int r = b.length - 1; while(l <= r){ int mid = l + (r - l) / 2; if(b[mid] > fen){&nbs百思特网p;r --; }else if(b[mid] < fen){ l++; }else{ // 由于存在分数相同的人,所以还要往后查找 while(mid < b.length && b[mid] == fen){ mid++; } return mid; } } return 0; }}
这里说明一下,输出的时候我没有输出"%"号哈 。
前缀和
不过这道题更好的做法是采用前缀和来做 。题设中每个同学的分数不超过 150,不小于 0,那么我们可以用一个数组 arr,然后让 arr[i] 表示分数不超过 i 的人数 。通过这种方式,我们可以把时间复杂度控制在 O(n+m) 。直接看代码吧,会更好理解(这里我就不写输入的代码了,用a[]存放成绩,m[]存放m次询问):