当你在面试中手撕算法时,会不会有这样的情况:
如果上述的情形戳中了你,那么恭喜你即将探索面试中的新的隐藏技能
——利用好你的面试官!简称“反向面试”!

学会这点,让你无痛提升面试水平,用崭新的视角来看待技术面。
本文分成两个部分:
下面是小目录:
[TOC]
不少朋友把全部的注意力都放在刷题上,一心争取面试中全部ace。
这样的努力当然是值得夸夸的,但是遗憾的是,在实际的面试中,“做出题目和“面试通过”并不能直接画等号。
面试更像是一场全方位的考量:
面试的底层逻辑是寻找高匹配、高潜力的优秀人才。
在校招场景中,大家经验相对都薄弱,而企业也愿意培养新人,所以展现出自己的潜力就更加重要。
潜力怎么体现呢?就在个人软实力中!
也许你并没有写出完美的代码,但是如果你展现出严谨的逻辑思维,训练有素的解题思路,从容自信的态度,对技术深深的热爱(热情不够,演技来凑!),跟面试官保持顺畅沟通…说不定也会深深打动ta!
说完了技术面试的选人标准,那我们该如何展现出这些能力呢?这就要提到我们的工具人——面试官!
跟独自刷题不同,面试是一场两个人的电影,充满了互动性和主观性。
面试官是一把双刃剑(面试官:是谁物化我qwq),利用的好就是你的offer小助手,利用不好就是感谢信问候。
普通码农眼里的面试官:考验我、为难我、威慑我的敌军!
高端码农眼里的面试官:一起完成精彩面试的队友!
大家就想象面试官是辅助你通关的角色,在面试的全过程都要注重跟ta的交流互动,让他感知到你的优秀!具体的做法在后面第二部分展开讲。
无论对于任何岗位,短期提升面试水平的最有效的方法,就是模拟面试。
技术岗也不例外,尤其是对于刷题还不错,但一到面试就紧张做不出来的同学,那请您务必模拟面试走起!
对于模拟面试,大家可能有些疑问。
Q1:自己一个人可以模拟面试吗?
A1:当然可以!就像学英语一样,如果没有小伙伴陪你练习,那么自己建立全英的环境也是不错的选择。假装面试官is watching you,你每次做题前就开启自言自语模式,确认自己的思路,写代码时也边写边讲解(划重点!这点是关键!),写完代码再讲一遍思路、分析复杂度。也许一开始有点奇怪,练习多了就适应这种方式了!
Q2:模拟面试需要注意什么呢?
A2:越贴近实际面试场景越好。不是做道某公司的真题就算模面了,而应该重视起来真实面试遇到的时间限制、follow-up questions、双向沟通 这些元素。再强调一下双向沟通的重要性,因为对于大多数人来说,写代码时讲话难免会影响思路,所以模面一定要刻意练习。
另一点就是注意复盘总结。你可以对面试/模面进行录音、录屏,事后来给自己各方面的能力表现进行打分,不断臻于完美。
Q3:模面好无聊,还有比模面更简单的方法吗?
A3:那就看别人的模拟面试吧~ ***有许多资源的,就当刷剧一样看。以他人为镜,总结别人面试的亮点和问题,也是很好的学习和反思的方法。
我记得我两年前看到过william(某计算机天才帅哥qwq)的模面视频,真的被震撼了,他不仅是世界顶级的竞赛选手,而且他把自己的思路讲得非常清晰(这道题蛮难的,但他竟然教会了我orz)。我也是从此把william当做榜样,练习这样的面试风格。
我们正式进入实战篇,跟大家分享面试的全流程中,那些心机的沟通小技巧。
我们以一道经典的面试题15. 三数之和为例。题目如下:
给你一个包含 n 个整数的数组 nums。判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
不要着急直接做题哦,推荐按照以下几个步骤进行。
step1:确定自己读懂题目。
这点非常关键,尽管面试题一般不会很难懂,但万一真理解错题意,写到一半儿才发现,不仅浪费时间,而且在面试官心中也超级减分。
如果你需要面试官的帮助,你可以大胆发问:
“题目中的xxx我有些不理解,您可以具体解释一下吗”
“请问能不能举个简单的例子呢,我想确认一下我是不是理解正确^ ^”
“我大概明白题目了,我确认一下,假如输入是xxxx,经过blablabla,输出应该是yyyy对吗”
总之,不用担心会显得很笨哦(当然,问问题的前提是自己思考过)。
step2:确认输入输出格式、边界条件等细节。
我们平时做题的时候,题面都是很清楚全面的,而在面试中可能是简化版。我们需要挖掘题目中被忽略的地方,跟面试官确认。
可以问哪些问题呢?以T15为例,我们可以询问:
我们是返回三元组的个数,还是返回三元组本身呢?
这些三元组以什么形式返回呢?二维数组可以嘛?
如果不存在这样的三元组,是返回一个空数组吗?
返回的三元组顺序有要求吗?
a,b,c可以为同一索引的值吗?
根据实际情况,向面试官适度问些这样的问题。意义:
读懂题之后就开始写代码了吗?大写的NO!
最稳妥的做法是:先确定解题思路,了然于心再动手敲代码。而不是走一步看一步,幻想山重水复疑无路(押!
step1:先分析暴力法等其他明显非最优解法。
依然是T15,在我开始想思路之前,我会先跟面试官说:
“这道题最容易想到的方法是暴力法,遍历所有的a、b、c组合,判断每个组合下是否相加为零。因为是三重循环,时间复杂度是O(n^3),空间复杂度是O(1)。”
然后过渡一下:
“暴力法做了一些冗余的比较,比如blablabla(举个例子),所以应该有更优的解法(也可以直接点明有O(n^2)的解法)。”
只是一个小示例。如果是有3+种解法的题目,也可以把每种解法和相应的复杂度都简述一遍,最后实现最优的,或者是面试官指定实现某个解法。
可能你会疑惑,讲这些非最佳方法真的有用吗?
step2:思考更优思路
情况1:如果题目非常陌生,一时半会儿没有想法,需要冷静思考,那么千万别直接沉默,否则会寂静的尴尬。
记住,我们可是要引领面试官的,时刻展现我们爱沟通爱协作的个人魅力。
你可以说:
“我可以先自己想一下吗?梳理好思路后再跟您沟通。”
“我有个大概的思路,但需要再思考一下,您稍等我一下可以吗?”
然后你就礼貌地赢得了短暂的沉默权!
情况2:已经有初步的想法思路了,无论是自己是否确定,都可以跟面试官先交流着。
继续T15,假如我已经想到用双指针了,尽管我还没思考“重复”怎么处理,但是没关系,先在整体思路上跟面试达成共识。
我会说:
“我觉得这道题可以用双指针来解决。首先对数组排序,这是对本题使用双指针的前提。遍历元素a,其他两个b、c元素使用相向双指针来确定。初始化b在a的后一位,c在数组最后一位,比较a+b+c与0的关系,如果小于0,那么b右移,如果大于0,那么c左移,直到b、c重合。”
还记得吗?面试官是我们的队友,不是对手。现在就是ta发挥价值的地方啦。
跟面试官对齐方法,可以引导面试官进入我们的思考过程,跟着我们的节奏走。只有充分明白我们的思路,才能更好地帮助我们。
具体有哪些帮助呢?
step3:举个用例,用自己的解法走一遍
尽管我们已经描述思路了,但是大部分题目单讲思路会很抽象。为了确保面试官明白我的思路,我再会找简单的例子,用我的解法来给ta过一遍。
你认为跑测试用例是代码就位后的环节?不是的,真正心机的人还没写代码就过用例了!
我一般是边讲边在IDE里写注释,亲测非常专业。遇到树图的问题,最好也提前准备好画图工具,边画边举例。
继续T15的例子,讲述完双指针的思路后,我会说:
“我举个例子吧,假设我们有个数组,数组元素是-1, -1, 0, 1, 2…”,
边说边在IDE里敲下(python):
# nums = [-1,-1,0,1,2]“初始化a是第0个元素,为-1;b是-1;c是2。此时相加正好是0”,
我加了一行表头a,b,c,例子呢就跟表头对齐。
# nums = [-1,-1,0,1,2]
# a, b, c
# -1, -1, 2 = 0“这时候移b移c都行,那我就把b右移一位吧,得到-1,0,2,相加是1,大于0。”
边说我又加了一行,
# nums = [-1,-1,0,1,2]
# a, b, c
# -1, -1, 2 = 0, so b ->
# -1, 0, 2 > 0, so c <-后面不再展开分析了,总之是借助IDE来清晰地展现出自己的解题思路。注意控制时间,例子中体现思路就可以,不一定解出答案。
这时候面试官不仅彻底懂你思路了,还可能对你印象很深刻呢。
如果举例这一步也没什么问题,那就开始写!代!码!
到了写代码的环节,如果你静悄悄地一言不发,面试官也不晓得你在写什么,ta可能很快就开小差了…不!我们要让他全神贯注,一整个拿捏住!
平时练习的“边说边写”就派上用场了对不对。假设你就是编程老师,面试官就是你的学生,你要实时地跟他讲解代码,带动他一起思考。
继续T15,我开始敲代码了,我边打字边解释:
“我们先定义一个函数,不妨叫做threeSum吧,输入是一个数组,输出是二维数组…”,
此时IDE中已经敲下了↓
def threeSum(nums: List[int]) -> List[List[int]]:我们继续:
“首先,我们将数组排个序,这步是O(nlogn)的复杂度…”
我习惯每个模块都阶段性总结一下复杂度,顺带就标在注释里了。也可以先不提复杂度,最后统一分析。
def threeSum(nums: List[int]) -> List[List[int]]:
# step1: sort,O(nlogn)
nums = sorted(nums)当我定义变量的时候,向面试官解释一下变量的含义。比如:
“我们建立
res数组,用来存放结果”
“下面开始遍历a,指针i指向的位置就是a”
def threeSum(nums: List[int]) -> List[List[int]]:
# step1: sort,O(nlogn)
nums = sorted(nums)
# step2: two pointers
res = []
for i in range(len(nums)):我们写if、while这样的语块前,也宏观地预告一下我们要做什么。比如:
“接下来我会比较三数之和与0的关系,可能是大于0,小于0,等于0这三种情况”,
说着边敲下这样的if-else分支,给面试官一种大局观的feel。
j, k = i+1, len(nums)-1
while j < k:
if nums[i] + nums[j] + nums[k] > 0:
...
elif nums[i] + nums[j] + nums[k] < 0:
...
else:
...以上的举例是想展示一下该如何边写代码边讲解思路,大家也可以根据自己的风格调整措词表达。
朋友们,边说边写真的是神仙面试方法:
从此写代码时养成自言自语的好习惯 OK?
代码写完之后,记得做两件事:
如果在总结环节,你突然意识到自己思路绕弯了,或者代码写的不简洁,也请主动跟面试官分享:
“我发现xx部分想复杂了,我觉得xxx这样做可能更清楚”。
面试官心里也是加分的,他会觉得你很爱思考,可能是面试紧张,你原本的实力会更高。
最后,面试官可能要求跑几个他指定的用例,顺利的话就结束这场撕题,或者进入到follow-up questions了。即使测试结果不对,也不用着急,因为按照上述的方法走下来,代码应该没有太大问题,而且我们的表现一直很好,可能有些细节没注意到。耐心地顺着自己思路,寻找出错的原因就好了。
尾声
以上就是一些个人的小经验。本文的初衷是我发现不少同学不太重视面试中的沟通交流,所以来分享我的tips。当然,我们不能舍本逐末,过于追求这些软实力,而忽视了技术实力的打磨。
如果有不同的想法,也欢迎在评论区理性讨论~