蚂蚁笔试
蚂蚁金服的笔试是我最早参加的,那时候还是第一次参加笔试,没啥经验,挺紧张的。具体题目我不记得了,但是感受还在。最后3个编程题1题满分,其他两题都只拿了部分分数,一直很可惜。
蚂蚁的笔试题还是比较全面的。因为开始编程题之前,有很多基础知识题,而且不能用本地IDE来解这些题,对我个人来说就挺烦。比如说有一题给定二叉树的后序,让你判断下面哪些中序遍历是可以构造出二叉树的,这种题让我编程实现的话,实现过N次了,但是手动模拟虽然知道怎么模拟,但是就很耗费时间(多选题要一个个模拟下去看看符不符合要求),容易焦虑。
到了编程题,因为前面已经消耗了很多时间,剩下的时间不多,我就比较着急。第一题看完匆匆忙忙写完就提交,发现过的样例不多,debug继续提交,最后拿了全部分数。第二题也是火速写完,是一个算月账单的题,写完之后发现只拿了部分分数,就一直找bug,浮点数转定点数也上了,愣是找不到(笔试完之后发现输出支出最大的月份,就是纯支出,不能把当月的收入用来抵消支出,导致输出错误),消耗了贼多的时间,导致最后一题没时间写。
看到编程题第三题,也就是最后一题,一眼下去没感觉,不知道怎么写,就先预处理出了前缀和,这样复杂度就到了O(n^2),最后写了这个暴力提交。提交完之后发现,第二个n的判断结果是有序的,也就是判断结果是111110000这样的形式,那么显然可以通过二分查找来优化第二个n。发现的时候还剩3分钟,我拿起键盘就是干,把第二个循环写成二分的形式,写完的时候发现还有几秒钟,马上调试,发现还有个小bug没改出来,然后就交卷了,二分的思路肯定是对的,再多一分钟可能就出来了,最后也太紧张了。
总结一个字就是赶。第一次在牛客上笔试,还没经验,以为题目只能顺序做下去,后来才发现可以跳着做。像第二题卡很多时间的原因还有一点,那就是过于自信,相信自己能调出来,殊不知错误的点在于题意理解的偏差。
网易互娱笔试
4.17号下午3点,笔试总共2个半小时,全是编程题,共有3道题目,我做了大概1个多小时就拿满分走人了。
T1是给定6个足球队,分为6行分别给出名字、积分、进球数、丢球数。最后再给3行表示最后三场比赛的结果,分别是 名字1,名字2,进球1,进球2。
属于简单的模拟题,只需要定义一个结构体,再把小于号重载一下就可以拿来排序输出了。
T2是阴阳师里面的御魂,有最多6个御魂坑,每个御魂的坑,可以放
该坑种类的御魂,御魂有两个属性,分别是暴击概率和暴击伤害。要求找到一种御魂搭配,使得暴击概率达到100的情况下,达到最高的暴击伤害。只看最后一句以为是二分,再看一眼,发现每个御魂的坑其实是独立的,不会影响其他御魂坑,具备最优子结构的特性。所以只需要定义一个dp数组,dp[j]表示暴击概率为j的情况下,能达到的最大暴击伤害。每次都枚举全部暴击概率(当然也可以是可能的暴击概率),看看能不能优化暴击伤害。
每次枚举一个御魂坑位的所有物品时,需要把上一次的状态存到tmp数组里,tmp=dp;状态转移方程 dp[j]=max(tmp[j-w[i]]+tmp[i],dp[j]),其中w[i]表示物品i的暴击概率,ack[i]表示物品i的伤害。
总的时间复杂度是O(n*C),n表示物品数量。C表示暴击概率的最大值,我用的是250,当然也可以100,但是要特判一下。个人感觉数据范围还是小了,可以更大。
T3给定一个地图,从S走到E,地图上有障碍物W,监控M,每回合可以走k步,回合结束的时候不能停在监控M的地方,问最少要几回合能走到E。个人觉得是偏向编码能力考验的题,算法考的不是特别深,就是简单的BFS。值得注意的就是走k步怎么处理,我先算了一下数据范围,发现暴力也能过,只要不重复走同样的格子,毕竟只有最多1w个格子。处理k步的方法也是很暴力,从队列里拿出一个位置后,把当前位置分别加入集合A,B。集合A表示当前这一步需要从集合A里的各个元素展开,集合B表示在这次k步过程中走过的所有点,用来防止来回走扩散出无数点。每次走完一步,就把所有当前步新加入的点放到集合A,等待走下一步。如果在搜索过程中能走到E那就直接返回用到了回合数就好了。只是这样的话是会超时的。还有一个剪枝就是如果搜到了一个位置,之前已经走过了,并且消耗的回合数比现在的少,那就不要再拿去搜了,因为停在那个位置+1个回合可以走k步,而当前搜的剩下步数是小于k的,所以不是最优的。这样就能拿到100%的分数了。
题目质量还是很好的,特别是第三题,如果思路不是特别清晰,写k步很容易写迷糊,还有去重。
字节笔试
4.17号晚上7点,总共2个小时,全是编程题,共4题。做了1个小时不到的样子拿了满分走人,过程还是很惊险的。
T1 是给定s,x,表示从s开始到s+x,[s,s+x)有哪些抢新股中签了。中签的概念就是s+x的末N位数和尾数相同。
我一开始没注意到。因为他没给数据范围,因为s可以很大我以为暴力循环必然超时。我就一直在想如何从尾数反推序列号,想了好久暂时也没想到什么优雅的办法,就抱着尝试的心态先写个暴力混分,从s循环到s+x,结果拿了60分,感觉还可以我就先切后面的题了。后面其他的都做完了回过头发现s可以最大到32位正整数,用int不太行,那就直接一步到位上longlong,也没必要unsigned int了,最后拿了满分。第一题分值最低却花了我近30分钟,当时还是有点慌的。
T2 是让你找一个最长的子数组,满足先增后减的形式。只需要预处理出每个位置的元素为最高点能够从往前扩展几格和往后拓展几格就可以做了。 时间复杂度为O(n),花了大概10分钟不到,也让我缓和了一下。
T3 是给你一个长度为n的数组,再给你一个整数b,让你求哪些子数组的和对b取余结果是0。看到子数组很果断的就上了前缀和,这样算一个子数组和就只需要O(1)的时间了,其次就是枚举子数组了,如果枚举左右边界的话很显然需要O(n^2)的时间,n最大是10w所以肯定不行。 想想两个前缀和的差值,对b取余结果是0,那不是就等于两个前缀和对b取余的结果相同吗。想到这个就可以用O(n)的时间复杂度来解决这题。当然我用的是map来记录和查询每个前面的前缀和出现每个余数的次数,查询和记录一次时间复杂度是O(logn),所以是总的时间复杂度O(nlogn),也可以转用unordered_map来达到O(1)查询、记录时间复杂度,考虑到map时间复杂度足够,而且可以少写几个字母就用map了。
T4是捡西瓜,总共有n个西瓜,每个西瓜两个属性,分别为重量和跳过西瓜数。跳过西瓜数就是捡了这个西瓜后,后面多少个西瓜不能捡。
这题一看就是一个动态规划题,应该是可以从后往前规划的。但是笔试的时候思考感觉比较繁琐,毕竟从后往前不太符合人的常规思路,就用了dfs,每次找从i个位置开始捡西瓜,最多能捡多少重量的西瓜,如果这个位置开始搜过了,我下次就不用搜了(记忆化)。
这样总共的时间复杂度就是O(n)。
总结来说笔试体验很好,除了第一题没给范围把我唬住了,废了不少时间。还好有经验先全部题目过一遍,最后回来刚第一题就没那么慌了。
最后
目前也就参加过这三家的笔试,希望一切顺利,能够找到好的工作。