先工程后算法:美国加州材料博后辞职到字节40万offer

七月在线实验室

共 4330字,需浏览 9分钟

 · 2021-03-23

1

个人情况介绍

我的个人经历十分特殊,100个人里可能都找不出一个。从个人背景到面试、工作入职的经历都比较奇葩,而且目前从事的这份工作title也不是算法工程师,所以这份面经整体的参考价值可能有限。不过我会尽量强调,在整个过程中,那些我个人认为很有用的准备工作,希望也能对你有所帮助。

先交待一下背景。我18年在美国南加州某学校拿到材料方向的博士学位。毕业时因为没及时找工作,外加老板认可,就先留在组里面做了一年半的博后。后来因为对科研彻底失去兴趣,我选择在尚未确定下家的时候离职。当时有一些面试,但都没能走到最后,眼看身份即将到期,我决定回国。


就当我20年三月准备回国的时候,恰逢COVID-19在美国大爆发,国际航班大规模被砍,只得滞留直到八月中才回国,隔离两周后开始准备找工作已经是九月了。现在这份工作是十月在牛客网上面的留学生专场抱着试试看的态度自己投的简历,几番波折以后,21年一月来到了字节跳动电商业务下面这个算法团队,做数据服务的后端开发。


在投工作面试期间,我也报名参加了七月在线NLP就业班,一是做好第二手准备,二是想系统地接触一下深度学习,以前的经历这块基本是空白。


说实在的,能拿到这个offer是比较幸运的,尤其是在我不知道自己到底算不算应届生的情况下。这边岗位应该是个社招岗位,可能是缺人的缘故,我虽然名义上没有工作经验,但简历还是被捞了,而且进入了面试流程。最后offer按普通校招定的级,总包算上房补、加班费能有40w。从我自身来看,能面过字节的技术岗,应该还是自身基本功ok,编程能力过硬。当然,我也是从小白慢慢成长过来的……这过程中有几个明显的milestone。

第一个milestone,是能设计出功能健全、易用且易维护的代码。


以前读博的时候,我的研究内容在材料这个大领域里面属于比较小众而且夸学科的——新能源材料的计算模拟。因为这种量化、数据驱动的研究性质,我们用python非常多。平时工作大部分是在写jupyter notebook处理分析数据,然后用matplotlib可视化放在ppt里跟老板开会用。这种快速试错的工作对于编程能力的要求并不高,和不少kaggle kernel一样面条代码满天飞。我最菜鸡的时候,曾经把结果用print输出出来,然后用浏览器的搜索功能计数(现在我当然知道应该用一个hash table/counter)。


我的编程能力第一次明显提高,是一个机缘巧合:有一个工作中要用到的模拟软件,与我们lab使用/开发的开源python分析包之间缺少一个io的模块,用于处理模拟软件的输入输出。由于我是用这个模拟软件最多的人,因此我志愿承担了这个工具开发的任务。先前有一版别人开发的io,但是考虑得不够周全,很多功能不支持甚至与我们需要的功能存在冲突。本来打算在此基础上重构,但因为对方代码基本没有测试,最后不得已重写了……前前后后搞了将近一个月,完成了这个1000+行的模块,外加用将近1:1测试代码量把测试覆盖率拉到95%以上。


现在回头看,这个milestone过后,我应该能胜任大部分的开发工作,而且还能灵活使用一些第三方库,比如这里用的numpy和pandas,丰富自己代码的功能。对大部分人来说,这个milestone可能需要在工作中积累,有一个代码习惯良好mentor(比如我老板)会加速这一步的成长,至于校招这里应该也不是考核的重点。


第二个milestone,是能够搞定面试中的手撕代码环节。


前一milestone如果叫胜任工作的话,这里的应该就叫通过面试。显然,大家都知道这一行是面试造火箭,工作拧螺丝,会拧螺丝还真不一定会造火箭。罗翔老师曾经说过,一个人天赋异禀,也要经过刻苦的训练才能成功。


我曾经在刚毕业那会儿面试过一家科技公司,总共两面,都跪在白板coding环节,被面试官劝返。后来找时间看视频恶补了一下数据结构和算法,便开始了leetcode。原先因为是打算找data scientist的工作,就基本专注于easy的题目。这期间经历了从看见two sum一脸懵,到后面熟练到不用十分钟搞定一道,最后基本刷完了当时库存的所有easy的题。


第二次捡起lc是20年三月滞留那段日子,给自己找点事做,1easy 2medium 1hard为一组,按题号做下去。这一次最后做了500+题目,停下来是因为后面题目的难度明显有提升(比如n-queens这个hard放到300+的位置顶多是个medium)。

网上流行一个刷前300题的说法,这些应该都属于经典面试题,在国内足以从容面对字节这样偏爱手撕代码的厂,国外的话对于很多厂(除了google)也够用了。还有一套剑指offer,难度不如lc,对于熟悉牛客网的OJ以及面试前热身打气比较有用。我在面试过程中,面试官给的题90%以上都是题号小于300的原题,下面会具体列出题号。


第三个milestone,是能够在不断变化的技术中思考抽象出不变的规律,并举一反三完成快速“迁移学习”。


举个不太恰当的例子:torch.tensor是可带有梯度值的numpy.array,因此可以使用numpy中类似的向量化计算来高效处理torch.tensor的运算(更大程度上是因为torch API与numpy看齐)。工作中我们可能使用到许多不同的编程语言、不同的框架、不同的机器学习算法。


全部掌握所有的技术是不切实际的。足够优秀的技术人员,都是根据面对的问题,由原先掌握的技术迁移到新的能够解决问题的技术。人们常说的终身学习,在拆解到把握问题本质后,似乎也不是那么难做到。这一层境界相比前两层要高出太多,本质上是鼓励大家平时勤思考,把握技术的精髓而不是盲目推崇某种技术,毕竟解决不了问题的技术真的一文不值。


下面还是把具体的面试交待一下。

2

笔试

两小时四道题,medium难度,不是原题,时间太久记不太清了。当时做得不太好,四道题都写了代码,但只有第三题OJ全部过了。


第一题很简单,但是OJ不过心态有点崩。最后一题是个二维的BFS/DFS,也不难,但代码里有bug,调试环境不熟最后时间到了。做完觉得没戏了,一门心思准备就业班上课了,结果一周后等来了HR电话……


2

三轮技术面后被鸽

对面是一个云计算下面负责机器学习的部门。二面不甚理想,问了一些简历上写的但答得不好。三面只做了手撕代码,虽然都做出来了,但面试官一副对我没什么兴趣的样子。手撕代码部分并不难,都是medium原题。之后就是等不来的HR面,直到两周后被电商这边捞起来……

一面


面试官是我现在合作最多的同事,上来先写代码。LC 146 LRU Cache,要求get put时间复杂度O(1)。我先是分析了一下满足O(1)时间复杂度需要哪两种数据结构的组合,然后说在python里面如果用OrderedDict可以正好满足这一需求。面试官听到这里并不想让我用库,只好手写链表……结果就是有些bug调不通,时间也耽误的比较久,接近一小时。


最后面试官及时结束了这个问题,又挖掘了一下我的简历(写得很烂),然后就愉快地结束了。


二面


面试官是我现在团队小方向里面唯一的senior,也是先写代码。第一题不记得了,但应该是个easy很快就过了。


第二题 LC 239 Sliding Window Maximum (居然是hard,后知后觉)。这是一道我非常喜欢的题,可以从最粗暴的解法一步步优化到最优解。之所以是hard大概是因为最优解用到了单调的栈/队列,这种套路在LC见多了可能也就不觉得难了。面试官这里也非常棒,先让我写最直观的解法,通过OJ后再通过讨论时间复杂度来探讨出优化的可能性,并最终指引我完成最优解。


之后面试官感觉还意犹未尽,问了一个有实际业务场景的题目。这里我感觉考察更多的应该是沟通能力,能把这个不太明确的需求逐步缕清规则并实现。


最后问了一些进程线程、数据库事务的八股文。之前的所有面试包括接下来的三面也没遇到网络、数据库、操作系统的问题,大概是因为他们看我不是科班出身吧……最终面试官当场反馈过了。


三面


面试官是我现在的团队leader,全程写代码。第一题LC 22 Generate Parentheses。比较经典的题,先用DP直接秒杀了。然后面试官问,能不能换一种做法?见招拆招,用backtracking也搞定了,有点小bug,不过及时发现了,问题不大。


面试官见我是老leetcoder了,抛出个大招,手写堆排序……野路子出身的我会写一些排序算法,但显然不包括heap sort。这个词听说过,一开始还以为是额外建一个堆然后再把数pop出来,后来真写完才意识到空间复杂度为O(1)。


现在回想一下,这个问题还是相当有难度的,涉及堆的定义、堆的数组实现、堆的调整(递归)等等,有点考察面试者拆解问题能力的意思,也有考察沟通能力的成分,尤其是在这种一脸懵又高压的状态……最后磕磕绊绊还是实现出来了,并且在面试官的帮助下把一些面条代码的逻辑简化了。


其实看视频对面面试官看我写不出来着急上火的样子,我以为会被挂掉。但临结束前面试官给我的反馈是“代码风格不错”,随后问了HR也说过了,真是刺激……


4

面试后续

入职以后我也观察了周围同事的做面试官会问什么样的问题。我们的团队有一半是算法工程师,面试时除了常规的手撕代码外,还会问算法技术的深度和广度。深度一般指简历上的项目,通常面试官会挖掘候选人对问题的处理方式。广度则是对常见算法的认知。


以前听别人说大部分落地的机器学习算法都属于监督学习,但恰恰我手头的一块业务就是在做无监督学习。在大部分业务强相关的部门,这种技术选型往往都是由业务决定的,而业务通常又是变幻无常的,所以会要求候选人有技术上的广度,在纷乱的业务中选择合适的技术实现落地。


知乎上有个回答说,想要做算法工程师,先要做一个合格的工程师。这句话在别的厂我不清楚,但在字节是绝对的真理。算法与开发可能工作内容的侧重有所不同,但二者共同的地方是要上线并迭代、维护自己的微服务,并且期待能接入业务,为使用方提供服务。这大概就是所谓的落地能力吧。



粉丝福利


【SVM与XGBoost】第五期 特训课

3.26日开课,

1元购课依然尊享499.9元购课所有特权。



课程其他的细节可以联系课程顾问来获取
添加课程顾问微信
报名、课程咨询
👇👇👇

点击"阅读原文",立即1元购买课程
浏览 42
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报