糟糕的面试问题:没有临时变量的情况下交换变量
巧妙的编程技巧在编程面试中毫无用武之地。它们通常只涉及少量代码,解决一些看似无害的问题,例如“找出链表中的循环”。面试官通常会附加一些不公平的限制,例如“你不能使用该语言的搜索功能”。这些技巧通常遵循高度具体且易于搜索的模式。然而,它们并非能够在面试中解决的问题。这些是研究级别的问题,需要随机的先验知识、幸运的直觉或大量的面试官提示。
识别不好的问题并理解它们造成的问题至关重要。例如,我来思考一个常见的面试谜语:“如何在没有临时变量的情况下交换变量?”这个问题会在面试中制造不必要的紧张感。这可不是你在工作中甚至个人项目中会遇到的编程问题。更令人不安的是,这个问题没有真正的“解决”方法。此外,它也无法透露任何关于候选人的信息。
这根本不是一个热身问题,而是一个不适合在面试中问的问题。
在日常编码中从未使用过
你走进面试室,和面试官握手,然后坐下。然后,面试官会平静地递给你一支白板笔,指着白板,问你:
如何在不使用第三个变量的情况下交换两个变量?
你把swap
函数写下来。或者你可能知道一门可以实现该功能的语言a,b = b,a
。太棒了!这只是一个简单的热身。
可是等等,你听到面试官大喊“犯规”了。“不,我不是这个意思。你不可以恰当地使用语言,而是需要做一些操作性的胡言乱语!”他们可能不会直接用这些词,但他们会这么说。
稍后我会回到巧妙的交换答案,但首先,让我们看看面试会发生什么。
给受访者带来紧张感
如果你以前没见过这个问题,你可能会陷入恐慌。或许你能比别人保持冷静,但你还是会感到不舒服。别为此感到难过;大多数人都会有同样的感受,而且是有原因的。
这个问题和你之前项目中的任何代码都不匹配。这道题不是你课堂上遇到的。你没有得到展示能力的机会,反而被扔进了水里,还在努力不让自己被淹死。
这有什么用?面试本身就已经够让人紧张的了。作为一个热身问题,这个问题可能会毁掉整个面试体验。面试官非但没有试图与你平起平坐,反而展现出他们的主导地位,把你压垮了。
我发现大多数求职者都已经很紧张了。当你走进门或拿起电话的那一刻,你可能就已经在发抖了。作为面试官,我的工作就是热情地接待你,让你平静下来。我想看看你在办公室的日常表现。
没有解决这个问题的方法
也许你保持理智,试图解决这个问题。但你可能会发现这个问题根本无法解决,至少在面试的范围内无法解决。
经验丰富的程序员可能会(我强调“可能”)注意到可逆运算符是必要的。异或和按位补码都能保留所有信息。他们也可能会注意到,使用二进制补码进行加减运算也符合条件。如果没有,面试官可能会提示他们这一点。
太好了,按顺序排列这些运算就能得到想要的结果。异或解法和另一种加/减法都使用了三个赋值操作和四个二元运算符。
让我们依靠一点魔法或面试官的提示。不知何故,你会得到解决方案的模板形式:? = ? ⊗ ?
重复三次(请参阅“巧妙答案”了解其来源)。这有(2 x 2 x 4 x 2) ^ 3 = 32768
多种组合可供尝试。借助一些关于交替变量的指导性见解,可以将其精简到 64 个,甚至 32 个解决方案。
现在你需要尝试所有 32 种组合,希望不出错,最终找到正确的答案吗?这需要多长时间?你需要用数学方法证明它是正确的吗?
谜题
通过添加严格要求,很容易将可解问题转化为难题。这在算法复杂性方面似乎很流行。
例如,你可能会被要求编写一个双端队列。一个好的面试官不会因为你不知道它是什么而扣分——它是一种可以从列表的头部和尾部推送和弹出数据的结构。作为一个 API 设计问题,我不介意这个问题,但我希望它更具体一些,一些日常编程中用到的东西。
让我们添加一个简单的要求:所有操作的摊销时间必须是 O(1)。即使你理解了这个问题,你仍然会面临一个难题。带约束的算法设计很难。除了强行推敲想法并借鉴多年的设计经验之外,没有其他明确的方法——我曾经用过这种方法,但有多少项目需要人们理解摊销时间呢?
这一类别中一个很常见的问题是“设计一个get_minimum()
时间复杂度为 O(1) 的堆栈”。这个看似简单的问题背后隐藏着很多秘密。这会让人感到非常不舒服。我在网上看到很多关于这个谜题的题目,其中很多题目都是错的,这让它变得根本无法回答。没有什么比一个措辞错误、没有有效答案的问题更让候选人感到不舒服了。然而,鉴于这个问题的流行程度,它就成了一个无关紧要的问题。
有些人偶然知道
就像大多数随机琐事一样,有些考生碰巧知道问题的答案。你可能只是碰巧以前见过这个问题,并且记得答案。我相信你会很感激这种轻松的优势,但我敢打赌,你不会觉得这是你应得的。其他人,只要花几分钟用搜索引擎搜索一下,也能找到答案。
如果问题的一部分是这样的,我觉得这很公平:你可以上网查找答案。能够在网上找到晦涩难懂的编码知识也是一种编程技能。
以下是人们被问到的一些琐事问题的例子:
- 2^32 是多少?它的意义是什么?你可以想象一下,招聘人员的屏幕上显示着“4294967296”这个数字,准备拒绝任何答错的人。这个数字的意义是指 32 位 CPU 的可寻址内存容量。从技术上讲,这个答案是错误的——冷知识题的另一个问题是,你需要猜出“正确”的答案。
- Python 中的默认排序算法是什么?可能是快速排序,或者是 C++ 用来优化性能的 Introsort(快速排序、堆排序和插入排序的组合)。你关心吗?我能不能假设它使用了一种高效的方法?不过说到 C++……
- 未定义行为和未指定行为之间有什么区别?这个问题背后隐藏着一个重要的概念,但如果你不能根据这些术语准确地解释,我个人会原谅你。
- 僵局的四个条件是什么?一位大学教授在考试中问到这个问题。面试又不是考试。
能通过搜索找到答案的问题都不是好问题。上班的时候,我可以上网,找到很多晦涩问题的答案。我不用在封闭的房间里,对着白板苦苦思索答案,耗费宝贵的大脑。我早就训练我的大脑不再记住那些琐碎的事情了。相反,我学会了良好的搜索技巧。
这或许会是一个有趣的面试前测试。我会给你十个不太容易理解的琐事,给你半个小时的时间去寻找答案。
面试官也应该记住,他们不仅仅是在评估我,我在评估他们。如果我被问到愚蠢的问题,我会对公司产生负面印象。即使我比其他候选人知道更多琐碎问题的答案,也无济于事——那样的话,我得到这份工作肯定不会感到高兴。
巧妙的交换答案
交换问题的标准答案之一是使用排他或。
if x != y
x = x ^ y
y = x ^ y
x = x ^ y
这“有效”,但仅适用于无符号整数。在许多语言中,有符号整数的具体位运算是未定义的。这个棘手的符号位可能会造成麻烦。此外,上述方法在 C 或 C++ 中也可能存在提升问题,因为类型可能会发生变化。此解决方案适用于少数类型:少数特定大小的无符号整数。
关于效率,毋庸置疑。在 CPU 层面,交换变量最终会变成一系列的加载和存储操作。对值执行操作会为这些加载和存储操作添加指令。此外,当嵌入到其他代码中时,优化器有时可以移除交换操作并直接使用源值。这种代码技巧很少算作优化,反而会降低代码速度。
询问有关位运算符的问题并没有什么错。很多职位都需要它们,而且所有程序员都应该理解。它们是布尔逻辑的扩展,我会毫不犹豫地拒绝那些不懂布尔逻辑的候选人。
但是如果你想问的是按位运算的问题,为什么不让考生对 UTF 文本数据进行编码和解码呢?它有具体的规范,不需要任何解题。而且这也是一种实用知识。
查找循环中的循环
曾经有人问我:“如何检测链表中的循环?” 这让我很紧张,但由于我之前做过图论题,所以觉得自己可以回答。我想出了一个可行的答案。然后又想出了一个。当面试官提示他们想要哪个答案时,我又想出了第三个答案。
我看到一些讨论说这个问题也很糟糕,我倾向于同意这种观点。如果我根据我在这里说的内容来评估一下会怎么样?有些候选人会知道答案,而其他人可以快速查找答案。如果你不知道怎么用,而且以前没有用过图表,你的压力水平就会突然上升。
然而,与变量交换相比,这里有几种方法。如果你对图和数据结构有所了解,那么你就可以从这里开始解答这个难题。如果你仍然一头雾水,面试官可以给你很多小提示,让你走上正确的道路,而不是直接给出答案。
这些代码在很多代码库中都会出现。如果工作需要这类工作,那么检查一下知识点是合理的。
如果面试官处理得当,这个问题或许可以接受:提供帮助,并且问出来又不让你感到震惊。但如果面试官只是问了一句“如何检测循环中的循环”,然后递给你白板笔,默默地往后靠,脸上带着一丝得意,那么这绝对算不上什么好问题。
更好的问题
那么,变量交换作为面试题有什么意义呢?当然,这是一个有趣的小谜题,但你希望你的员工解决这些谜题,还是写出高效的代码呢?
在面试中使用问题之前,请先思考一下我之前提到的几点。这个问题会让候选人感到受欢迎,还是会让他们感到不必要的不安?它是否涉及到你经常看到的代码?这个问题在面试中能得到合理的解决吗?它是鼓励候选人学习一些琐碎的知识,还是探索候选人能力的某种应用?
经过深思熟虑的问题会对您、您的公司和候选人都有好处。
我在interviewing.io上进行过很多面试——可以去那里练习面试。我还在搭建一个新网站,帮助大家进行面试。加入邮件列表,成为第一批访问面试课程的人。
文章来源:https://dev.to/mortoray/terrible-interview-question-swap-variables-without-a-temporary-22jp