反向面试|教你如何拿捏面试官
22521
2022.08.10
2022.08.10
发布于 未知归属地

当你在面试中手撕算法时,会不会有这样的情况:

  • 审题比周赛还快,面试官话音刚落,你就迫不及待敲起了代码。
  • 人狠话不多,写代码的时候静悄悄,全世界只能听见清脆的键盘声。
  • 一旦思路走不通,表面强装淡定,但暗自着急,内心独自枯萎。

如果上述的情形戳中了你,那么恭喜你即将探索面试中的新的隐藏技能

——利用好你的面试官!简称“反向面试”!

image.png

学会这点,让你无痛提升面试水平,用崭新的视角来看待技术面。

本文分成两个部分:

  • 心法篇:分析技术面试的底层逻辑,讲清“反向面试”的动机和意义
  • 实战篇:保姆级教学面试方法论,对于面试中的各个环节逐步拆解!

下面是小目录:
[TOC]

第一部分:面试心法

心法一:技术面试不仅是考察技术

不少朋友把全部的注意力都放在刷题上,一心争取面试中全部ace。

这样的努力当然是值得夸夸的,但是遗憾的是,在实际的面试中,“做出题目和“面试通过”并不能直接画等号。

面试更像是一场全方位的考量:

  • 代码写的正不正确、优不优美,体现的是技术能力;
  • 清晰地阐述解题思路,分析复杂度,体现的是解决问题的能力;
  • 跟面试官保持良好的互动,体现的是沟通能力和团队协作精神……

面试的底层逻辑是寻找高匹配、高潜力的优秀人才。

在校招场景中,大家经验相对都薄弱,而企业也愿意培养新人,所以展现出自己的潜力就更加重要。

潜力怎么体现呢?就在个人软实力中!

也许你并没有写出完美的代码,但是如果你展现出严谨的逻辑思维,训练有素的解题思路,从容自信的态度,对技术深深的热爱(热情不够,演技来凑!),跟面试官保持顺畅沟通…说不定也会深深打动ta!


心法二:面试是一场双向奔赴

说完了技术面试的选人标准,那我们该如何展现出这些能力呢?这就要提到我们的工具人——面试官!

跟独自刷题不同,面试是一场两个人的电影,充满了互动性和主观性。

面试官是一把双刃剑(面试官:是谁物化我qwq),利用的好就是你的offer小助手,利用不好就是感谢信问候。

  • 普通码农眼里的面试官:考验我、为难我、威慑我的敌军!

  • 高端码农眼里的面试官:一起完成精彩面试的队友!

大家就想象面试官是辅助你通关的角色,在面试的全过程都要注重跟ta的交流互动,让他感知到你的优秀!具体的做法在后面第二部分展开讲。


心法三:熟能生巧 Practice Makes Perfect

无论对于任何岗位,短期提升面试水平的最有效的方法,就是模拟面试。

技术岗也不例外,尤其是对于刷题还不错,但一到面试就紧张做不出来的同学,那请您务必模拟面试走起!

对于模拟面试,大家可能有些疑问。

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 且不重复的三元组。


互动一:问清题目 Ask Clarifying Questions

不要着急直接做题哦,推荐按照以下几个步骤进行。

step1:确定自己读懂题目。

这点非常关键,尽管面试题一般不会很难懂,但万一真理解错题意,写到一半儿才发现,不仅浪费时间,而且在面试官心中也超级减分。

如果你需要面试官的帮助,你可以大胆发问:

“题目中的xxx我有些不理解,您可以具体解释一下吗”

“请问能不能举个简单的例子呢,我想确认一下我是不是理解正确^ ^”

“我大概明白题目了,我确认一下,假如输入是xxxx,经过blablabla,输出应该是yyyy对吗”

总之,不用担心会显得很笨哦(当然,问问题的前提是自己思考过)。


step2:确认输入输出格式、边界条件等细节。

我们平时做题的时候,题面都是很清楚全面的,而在面试中可能是简化版。我们需要挖掘题目中被忽略的地方,跟面试官确认。

可以问哪些问题呢?以T15为例,我们可以询问:

我们是返回三元组的个数,还是返回三元组本身呢?

这些三元组以什么形式返回呢?二维数组可以嘛?

如果不存在这样的三元组,是返回一个空数组吗?

返回的三元组顺序有要求吗?

a,b,c可以为同一索引的值吗?

根据实际情况,向面试官适度问些这样的问题。意义:

  1. 进一步帮助自己理解题目
  2. 稍后写代码时会更注意细节
  3. 向面试官体现自己的严谨和专业度(叉腰!

互动二:确认思路 Explain Your Thoughts

读懂题之后就开始写代码了吗?大写的NO!

最稳妥的做法是:先确定解题思路,了然于心再动手敲代码。而不是走一步看一步,幻想山重水复疑无路(押!


step1:先分析暴力法等其他明显非最优解法。

依然是T15,在我开始想思路之前,我会先跟面试官说:

“这道题最容易想到的方法是暴力法,遍历所有的a、b、c组合,判断每个组合下是否相加为零。因为是三重循环,时间复杂度是O(n^3),空间复杂度是O(1)。”

然后过渡一下:

“暴力法做了一些冗余的比较,比如blablabla(举个例子),所以应该有更优的解法(也可以直接点明有O(n^2)的解法)。”

只是一个小示例。如果是有3+种解法的题目,也可以把每种解法和相应的复杂度都简述一遍,最后实现最优的,或者是面试官指定实现某个解法。

可能你会疑惑,讲这些非最佳方法真的有用吗?

  1. 对自己而言,能帮助自己确定复杂度的上界。同时,发现暴力解法中的弱点,有助于提供思路。
  2. 对面试官而言,让他一开始就看到你的解决问题的能力、表达能力和复杂度分析能力!成功引起他的注意,让他后面认真听你讲话,不会走神!

step2:思考更优思路

情况1:如果题目非常陌生,一时半会儿没有想法,需要冷静思考,那么千万别直接沉默,否则会寂静的尴尬。

记住,我们可是要引领面试官的,时刻展现我们爱沟通爱协作的个人魅力。

你可以说:

“我可以先自己想一下吗?梳理好思路后再跟您沟通。”

“我有个大概的思路,但需要再思考一下,您稍等我一下可以吗?”

然后你就礼貌地赢得了短暂的沉默权!


情况2:已经有初步的想法思路了,无论是自己是否确定,都可以跟面试官先交流着。

继续T15,假如我已经想到用双指针了,尽管我还没思考“重复”怎么处理,但是没关系,先在整体思路上跟面试达成共识。

我会说:

“我觉得这道题可以用双指针来解决。首先对数组排序,这是对本题使用双指针的前提。遍历元素a,其他两个b、c元素使用相向双指针来确定。初始化b在a的后一位,c在数组最后一位,比较a+b+c与0的关系,如果小于0,那么b右移,如果大于0,那么c左移,直到b、c重合。”

还记得吗?面试官是我们的队友,不是对手。现在就是ta发挥价值的地方啦。

跟面试官对齐方法,可以引导面试官进入我们的思考过程,跟着我们的节奏走。只有充分明白我们的思路,才能更好地帮助我们。


具体有哪些帮助呢?

  1. 如果我们有没考虑周全的地方,面试官会提醒我们,比如这道题,面试官可能会问“那你怎么保证三元组不重复呢”。
  2. 如果我们整个思路就是错误的,面试官会及时把我们拉回来的,有可能直接指出来,有可能给你个用例让你自己发现方法行不通。
  3. 如果我的思路不是他想要的,他可能会说“我明白你的方法了,不过还有更优的解法,你可以再想想”。这样也很好,实时了解面试官的想法,不会浪费时间。
  4. 如果我们思路无敌正确,面试官一般会给出比较正面的回复,也可能比较委婉,比如“听起来没有什么问题”,“那你代码实现一下吧”。

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来清晰地展现出自己的解题思路。注意控制时间,例子中体现思路就可以,不一定解出答案。

这时候面试官不仅彻底懂你思路了,还可能对你印象很深刻呢。

如果举例这一步也没什么问题,那就开始写!代!码!


互动三:边写边说 Talk While You Code

到了写代码的环节,如果你静悄悄地一言不发,面试官也不晓得你在写什么,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)):

我们写ifwhile这样的语块前,也宏观地预告一下我们要做什么。比如:

“接下来我会比较三数之和与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:
		...

以上的举例是想展示一下该如何边写代码边讲解思路,大家也可以根据自己的风格调整措词表达。

朋友们,边说边写真的是神仙面试方法:

  1. 面试官能跟着你的思路走,了解我们的思考过程。
  2. 当我们思路卡顿的时候,因为面试官跟上我们了,ta可以给予适当的提示(因为他知道这道题的解法呀!)。这也就是我们强调的“利用”面试官。
  3. 当我们沉浸写代码的时候,可能会有一些自己没留意的简单语法错误和逻辑错误,面试官作为旁观者,会及时提醒纠正。这样的话,不至于等到最后跑用例error时再找bug在哪里。另外,即使最后运行的时候报错,面试官都不好意思给你减分,因为他全程跟着你的思路而他也没看出来!

从此写代码时养成自言自语的好习惯 OK?


互动四:总结分析 Summarize and Analyze

代码写完之后,记得做两件事:

  1. 有始有终,整体再简述一遍代码思路。用鼠标引导着面试官视线,简单介绍写的每个模块做了什么事情。
  2. 分析复杂度。分析每个步骤的时间复杂度是多少,最终整个方法的时间复杂度。还有空间复杂度是多少。

如果在总结环节,你突然意识到自己思路绕弯了,或者代码写的不简洁,也请主动跟面试官分享:

“我发现xx部分想复杂了,我觉得xxx这样做可能更清楚”。

面试官心里也是加分的,他会觉得你很爱思考,可能是面试紧张,你原本的实力会更高。

最后,面试官可能要求跑几个他指定的用例,顺利的话就结束这场撕题,或者进入到follow-up questions了。即使测试结果不对,也不用着急,因为按照上述的方法走下来,代码应该没有太大问题,而且我们的表现一直很好,可能有些细节没注意到。耐心地顺着自己思路,寻找出错的原因就好了。

尾声

以上就是一些个人的小经验。本文的初衷是我发现不少同学不太重视面试中的沟通交流,所以来分享我的tips。当然,我们不能舍本逐末,过于追求这些软实力,而忽视了技术实力的打磨。

如果有不同的想法,也欢迎在评论区理性讨论~

评论 (44)