微软(苏州)面试经历:从入门到入职
年末,微软面试终于告一段落,目前已经签定 Offer Letter,处于背调阶段,不出意外的话,月底就会入职。
在准备面试的过程中,一众大佬的面经给了我很多启发,如今到了薪火相传的时候,希望我的面经对你也能有所帮助。
微软内推,可以发送邮件至 progcz@yeah.net,记得附上简历、心仪的岗位及链接(可以官网搜索)和简单的自我介绍哦。
1 背景
面经,向来是典型的「小马过河」问题。不同的人有着不同的教育和工作经历,装备等级在一定程度上影响着打怪难度,所以你我的背景越相近,面经才越具备参考价值。
1.1 教育经历
2017 年本科毕业于厦门大学测控技术与仪器专业,2020 年硕士毕业于中国科学技术大学控制工程专业。所以,我并非计算机科班出身,更多是靠选修和自学来接触的编程。
1.2 工作经历
2020 年入职字节跳动(上海),担任推荐算法工程师。至于为什么离开字节,我想这应该是下一篇文章的主题了,写在正式离开字节之后。
1.3 面试岗位
微软(苏州),Windows 365 软件开发工程师。
JD 参考:https://careers.microsoft.com/us/en/job/1168023/Windows-365-Software-Engineer
2 简历
如下所示,我并没有套用模板,只是参考了下简历一般需要哪些信息,然后用 Word 最基础的功能,做了一份够简的简历出来。
几点可能有用的建议:
准备中、英两版简历,做在同一个 Word 文件中,导入同一个 PDF 文件中。
保持简洁,重要的信息,尤其是与所面岗位相契合的信息,应该大书特书,占最大的版面。
3 人生问题
开个文档,针对面试中常见的人生问题,把答案提前准备一遍,每个答案都尽量保持在 5 - 10 分钟。
准备的过程,其实也是与自己对话的过程,因此这样做并不是为了弄虚作假,而是为了在被问到的时候,能够从容应对,逻辑清晰地表达内心想法。
比如:
为什么想离开上一家公司?为什么想加入我们这家公司?
简单介绍一下简历上的某个项目?你在其中承担哪一部分的工作?遇到最大的挑战是什么?
未来的职业规划是什么?想成为一个什么样的工程师?
简单介绍一下自己的优缺点?
有什么想问我的吗?
4 算法题目
优先刷下 LeetCode 的 Top Interview Questions,难度在 Medium 及以下即可。
几点可能有用的建议:
每道题目限定 20 分钟,没做出来直接去看 Discuss 里 Most Votes 的答案(如果英文吃力,可以参考 LeetCode All in One 项目),看完之后自己手写一遍。
不要满足于仅一种解法,要问这么几个问题:
现在这个解法,时间复杂度、空间复杂度是多少?
还有没有解法,可以降低时间复杂度,或者降低空间复杂度,或者写法上更简洁?
会讲思路,在写代码前能把解法口头描述出来。
会写测试代码和测试用例,在运行前能考虑到尽量多的 corner case,在运行后能根据 error case 分析代码中的 bug。
面试过程中,推荐使用 LeetCode 的 Playground 编写代码,相比 Codeshare,Playground 可以在线编译并运行,测试起来非常方便(微软的面试官都非常注重测试)。
比如,我在常见排序算法的 C++ 实现、复杂度和稳定性分析中给出的 Playground:
5 面试
简单记录一下我的面试过程,以供参考。
5.1 第一轮面试
常规,聊工作项目,做算法题目。
算法题目:给定一个由
0
和1
组成的矩阵,从左上角出发,只能向右或向下移动,0
表示可以通行,1
表示不可通行,求解到达右下角的不同路径的数量。原题参考:LeetCode 63. Unique Paths II解法:动态规划,维护一个同样尺寸的矩阵,矩阵中的每个值代表从左上角到这一格的不同路径的数量,那么容易得到,每个值都是其左侧格(如有)的值与其上方格(如有)的值之和,而该矩阵左上角的值确定为
1
,则从左上角开始遍历更新,最终返回右下角的值即可。上述解法写完之后,我主动与面试官进一步讲了,如何将空间复杂度从
O(n^2)
优化至O(n)
:不需要维护整个矩阵,只需要维护遍历位置的当前行即可。我相信这应该是个加分项。
5.2 第二轮面试(连续三场)
连续三场面试真的很累,一定注意精力管理。
第一场
科大师兄,聊学校,聊毕业论文(这个让我有点意外,我以为社招只会聊工作项目),做算法题目。
算法题目:给定一个
long long
类型的数字,以long long
类型返回其 reverse 后的数字。相似题目参考:LeetCode 7. Reverse Integer解法:题目并不难,主要考察如何处理 corner case,比如负数、结果值溢出、中间值溢出等情况。
第二场
常规,聊工作项目,做算法题目。
算法题目一:给定一个尺寸为 n 的数组,其值均在 [1, n+1] 之间,有且只有一个数字不在这个数组中,找出这个数字。
解法:题目并不难,实际上简单的数学运算就可以,但是面试官还是问了有没有其他解法,最后写了一个使用两轮异或运算的解法。
算法题目二:给定一个数组和一个目标值,在数组中找到三数之和,使其最接近目标值。原题参考:LeetCode 16. 3Sum Closest
解法:面试过程中只给了暴力解法,面试结束后才想起来,使用头尾双指针的解法,可以把时间复杂度优化到
O(n^2)
。
第三场
科大师兄,聊工作项目,问 C++ 题目,做算法题目。
C++ 题目:C++ 11 相比于 C++ 98,有什么新特性?智能指针
unique_ptr
是怎么实现资源独占的?答案:第一个问题老生常谈,可以参考面试中常见的 C++ 问题汇总;第二个问题,面试过程中猜错了,正确答案是
unique_ptr
使用= delete
禁用了拷贝构造函数。算法题目:对于带有随机指针的链表,进行深拷贝。原题参考:LeetCode 138. Copy List with Random Pointer
解法:第一轮遍历,先不考虑随机指针的拷贝,遍历原链表,构造新链表,在遍历过程中,将新链表节点的随机指针指向原链表节点,同时维护从原链表节点到新链表节点的映射;第二轮遍历,遍历新链表,从新链表节点的随机指针找到原链表节点,再从原链表节点的随机指针找到原链表随机节点,再从映射找到新链表随机节点,赋值给新链表的随机指针即可。
解法的难度是一方面,测试的难度才是真正考察的点。
在面试过程中,为了方便测试,我实现了
MyListNode* vec2list(vector<pair<int, int>>& vec);
将测试用例从数组形式构造为链表形式,实现了bool valid(MyListNode* root_1, MyListNode* root_2);
用来判断两个链表是否互为深拷贝的关系。尤其是
valid
这个函数,千算万算还是百密一疏,面试官最后指出了其中可能存在的漏洞。
5.3 第三轮面试
最后一面是跟老板(竟然也是科大师兄)面,邮件里的 PRINCIPAL GROUP SW ENG MGR 格外显眼。
其实能到最后一面,说明候选人在技术方面没什么太大问题,老板考察更多的是,候选人是否具备成为优秀工程师的基本素养。
人生问题:
为什么想离开字节,为什么想加入微软?
希望成为一个什么样的工程师?
在字节有什么样的成长?
对 Windows 365 产品有什么样的理解?
算法题目:实现 sqrt 运算,计算算术平方根,结果向下取整。原题参考:LeetCode 69. Sqrt(x)
解法:二分法。