嘘……你的面试官也不知道他那些技术问题的答案!





5.00/5 (3投票s)
关于在面试中提出合适技术问题的建议
编写代码求 1 到 100 的和
对于那些看似简单的问题,人们必须格外小心,例如,求 1 到 100 的所有数字之和。一个简单的求和循环不足以让你的面试官满意。他希望你能给出 O(1) 时间复杂度下的答案。当然,我给出了和八岁的数学神童 卡尔·弗里德里希·高斯 当年一样的答案。
故事是这样的,卡尔·高斯的老师为了休息一下,给班级布置了一个问题,让他们计算 1 到 100 的所有整数之和。但高斯发现了一个规律,将首尾数字相加可以得到平均值 50,这使他能够得出计算公式。
1 + 99 = 100, avg = 100/2 = 50
2 + 98 = 100, avg = 100/2 = 50
3 + 97 = 100, avg = 100/2 = 50
.
.
.
47 + 53 = 100, avg = 100/2 = 50
48 + 52 = 100, avg = 100/2 = 50
49 + 51 = 100, avg = 100/2 = 50
原来,新加坡的教育体系会教小学生这个高斯技巧。
我想问读者一个问题:这是否意味着每个新加坡人,包括我,都经历过新加坡的教育,都像高斯一样有天赋?更大的问题是,面试官是独立想出这个答案,还是从网上看到过?如果问一个你自己都无法回答的问题,那是不公平的。
当然,仅仅因为你刚从别人那里得知答案,并不能 legitimate 地让你成为专家。然而,事实上,不少面试官确实认为,如果你能给出高斯的答案,或者使用异或(XOR)来交换两个整数,你的编程技能一定达到了惊人的水平。这简直是荒谬至极!
不使用临时变量交换两个整数
一个常见的面试问题是,要求求职者不使用第三方变量交换两个整数。
X := X XOR Y
Y := Y XOR X
X := X XOR Y
如果你通过临时变量进行交换,并在 Godbolt 编译器浏览器上查看汇编指令,你会注意到编译器不会将代码优化为 XOR 交换,因为 XOR 交换要正常工作,必须有一个检查来确保两个变量不相同,而这个检查会使执行速度比使用第三个变量的交换方法慢。而且 XOR 交换只能用于整数,不能用于其他类型:它不能用于交换指针。因此,要求提问者事先充分研究问题的有用性是不过分的。
编写代码,在不使用加号的情况下进行加法运算
即使是我这样的电子工程毕业生,在现场也很难回忆起全加器电路并将该电路转化为代码来回答这个问题。这个问题和 Lee 算法是来自电子领域的谷歌面试题。
只有那些微鼠(micromouse)团队成员才熟悉 Lee 算法,因为微鼠用它来解决迷宫。Lee 算法是一个非常简单的算法,机器人从值较高的单元格移动到值较低的单元格。每个单元格的值由其四个相邻单元格的最小值加一决定。Lee 算法是我所知道的最简单的算法,但即使是它也有其自身的复杂性,只有实现者才能了解。在我看来,狭隘的电子相关问题应该避免,除非组织属于该行业。
稍微跑题一下,对于那些对 Lee 算法感兴趣的读者,可以阅读我的文章!
嵌入式系统面试题:冒泡排序
如果求职者申请新加坡的嵌入式系统职位,很可能会被要求在没有伪代码或指令的情况下编写一个冒泡排序函数!我承认这个问题难倒了我。为什么是冒泡排序,最慢的那个?为什么不是插入排序或其他高效的排序算法,如归并排序?有时,这是测试中的唯一面试题。我问我的测试员有多少人能正确回答。他若无其事地说,几乎所有人。显然,嵌入式领域的每个求职者都烂记于心了冒泡排序。就像一些程序员为了面试而烂记于心 XOR 交换一样。
诚然,我对嵌入式系统编程工作和职责的具体内容并不熟悉,这可能是裸机系统中唯一可行的排序算法,因为在裸机系统中,每一个内存都必须预先分配,并且要排序的项的数量很小。所以,这可能是一个对嵌入式程序员来说合理的问题。
许多招聘经理几十年前就毕业了,没有跟上软件开发的最新发展。在我看来,编码测试应该仅限于测试解决问题的能力,而不是涉及对可以轻松谷歌到的信息进行死记硬背,或者可能被编译器捕获的语法错误。
有什么好的简短提问例子吗?
列举了这么多糟糕的提问示例后,那么有什么好的例子呢?我的意见是,问一个有简短答案的问题,以现场测试解决问题的能力。避免在面试书中找到的问题,因为候选人可能在书中读到过答案,除非他给出了一个不同的但正确的答案。
这是我一个好问题的例子。编写一个自定义的 add
函数来检测溢出,并在检测到溢出时抛出 OverflowException,而不使用 checked 关键字。
uint add(uint a, uint b)
{
const uint max_uint = 0xFFFFFFFF;
if(b > (max_uint - a))
throw new OverflowException();
return a + b;
}
这种检测可以通过汇编代码实现:执行 add
操作,然后检查 FLAGS
寄存器中的进位标志(用于无符号算术)或溢出标志(用于有符号算术)。
另一种方法是询问候选人是否了解概念,并让他解释概念。不要惊讶:许多经验丰富的程序员并不理解死锁,或者不知道受保护的访问级别。
回顾
在文章结束之前,让我们回顾一下上面提到的面试建议中的“应该做”和“不应该做”。
- 避免问技术面试官自己无法推导出答案的难题,并且候选人事先知道答案的可能性很高。
- 在面试前深入研究问题/答案。
- 除非组织属于该行业,否则避免问狭隘的电子相关问题。
- 问题应测试候选人的解决问题的能力。
- 问题的答案不应涉及对可轻易谷歌到的信息的死记硬背,也不应涉及可被编译器捕获的语法错误。
- 避免使用面试书中出现的问题,因为候选人可能在书中读到过答案。
- 询问候选人是否了解某个概念,并让他解释该概念,以了解他对该概念的理解程度。
历史
- 2020 年 1 月 12 日:初始版本