编写代码只是面试过程的一部分。
实际解决逻辑问题只是代码编写任务的一部分。
采访者希望确保:
您可以编写代码。许多在语言方面具有十年专业经验的应聘者根本不会编写任何代码,而该测试旨在拒绝这些应聘者。
在编写代码之前,请先考虑问题。许多人会跳到键盘上,写几十行代码,然后发现他们误解了最初的问题,因为他们没有花时间去思考它。
您可以在编写代码时适应自己。假设您找到了解决方案,但是当您开始实施它时,似乎您的第一个想法并不是最好的想法。您可以快速切换到更好的代码,最终重构您编写的代码吗?
这也意味着这种采访应该更具互动性。不用单手打字,而是购买免提工具包或通过Skype打电话并使用耳机。在工作中输入内容时输入内容,同时评论和解释您的工作:这会突然变得不那么尴尬。
您完成结对编程了吗?如果是,则采访情况非常相似,不同之处在于采访者可能不会给您他的意见,并且在结束后您也不会要求他与您切换键盘。
以下是一些纯数学问题的示例,以及它如何显示开发人员的非数学技能。
示例1:简单的编码练习
您需要在JavaScript中实现斐波那契数计算器。您应该能够更改索引。斐波那契数列遵循以下规则:
- 序列的前两个数字是0和1
- 每个后续数字是前两个数字的和。
示例:F 0 = 0,F 1 = 1,F 2 = 1,F 3 = 2,F 10 = 55。
你三分钟
在这里,面试官希望您尽快思考,找到解决方案并快速实施。这样的练习与实际开发人员的工作无关,并且与您获得CS学位时所能找到的东西更接近,但是面试官喜欢这种事情,所以让我们开始吧。而且,由于时间限制,不可能进行任何自动化测试,因此面试官可能不会期望您这样做。
“算法的描述使我想到了递归。第二条规则导致以下递归函数。”
var fibonacci = function (n) {
return fibonacci(n - 2) + fibonacci(n - 1);
};
console.log(fibonacci(10));
“为了结束递归,我们将通过替换fibonacci
函数主体来添加特殊情况。”
switch (n) {
case 0: return 0;
case 1: return 1;
default: return fibonacci(n - 2) + fibonacci(n - 1);
}
“完成。”
结论
正如我所说,这种练习与开发人员的实际工作完全无关。它使它变得毫无意义吗?并非如此,至少因为它表明此人:
能够思考问题。一些候选人将完全迷失方向,在压力下,他们将花费比分配的时间更多的时间来思考解决问题的可能方法。
知道递归或能够通过普通循环规避递归。稍后,访调员可能会问是否有使用/不使用递归的方法,以及递归的好处/缺点是什么。
了解编程语言的基础知识。使用人员switch
,保护子句,条件语句还是字典都没有关系:根据背景,不同的候选人将选择不同的工具来完成同一件事。
始终专注于问题,而不会带来单元测试,可伸缩性或性能等问题。然后,面试官可能会问,为什么在绩效方面,上述职能很糟糕,希望候选人解释应该采取什么措施才能使绩效达到合理水平。
示例2:棘手的问题
您需要在JavaScript中实现斐波那契数计算器。它应该尽可能快。您应该能够将索引的范围从0更改为100。斐波那契数列遵循以下规则:
- 序列的前两个数字是0和1
- 每个后续数字是前两个数字的和。
示例:F 0 = 0,F 1 = 1,F 2 = 1,F 3 = 2,F 10 = 55。
你三分钟
现在,我们有一个有趣的约束条件,它表明面试官并不真正在乎候选人解决问题的能力,而是在乎他猜测哪些方法比其他方法更快的能力。
这些棘手的问题通常会邀请棘手的答案。在给定时间限制的情况下,无法进行多种实现,对其进行基准测试,剖析最快的实现并提供最佳解决方案。
相反,该怎么办:
“让我Google“第一个斐波那契数字” ... 这看起来很有希望。使用一个简单的(可能是oxymoron)正则表达式,我们可以构建一个用逗号分隔的值列表。”
sed -e "s;\([0-9]*\) \([0-9]*\);'\2',;g" fbncc10.txt | tr '\n' ' '
“最后,程序本身。”
var map = ['0', '1', '1', '2', '3', '5', '8', '13', '21', '34', '55', '89', '144', '233', '377', '610', '987', '1597', '2584', '4181', '6765', '10946', '17711', '28657', '46368', '75025', '121393', '196418', '317811', '514229', '832040', '1346269', '2178309', '3524578', '5702887', '9227465', '14930352', '24157817', '39088169', '63245986', '102334155', '165580141', '267914296', '433494437', '701408733', '1134903170', '1836311903', '2971215073', '4807526976', '7778742049', '12586269025', '20365011074', '32951280099', '53316291173', '86267571272', '139583862445', '225851433717', '365435296162', '591286729879', '956722026041', '1548008755920', '2504730781961', '4052739537881', '6557470319842', '10610209857723', '17167680177565', '27777890035288', '44945570212853', '72723460248141', '117669030460994', '190392490709135', '308061521170129', '498454011879264', '806515533049393', '1304969544928657', '2111485077978050', '3416454622906707', '5527939700884757', '8944394323791464', '14472334024676221', '23416728348467685', '37889062373143906', '61305790721611591', '99194853094755497', '160500643816367088', '259695496911122585', '420196140727489673', '679891637638612258', '1100087778366101931', '1779979416004714189', '2880067194370816120', '4660046610375530309', '7540113804746346429', '12200160415121876738', '19740274219868223167', '31940434634990099905', '51680708854858323072', '83621143489848422977', '135301852344706746049', '218922995834555169026', '354224848179261915075'];
var fibonacci = function (n) {
return map[n];
};
console.log(fibonacci(10));
结论
棘手的问题邀请棘手的答案。不要太英勇,只有三分钟的时间也不要开始进行基准测试和性能分析。考虑使用您的经验来解决问题的聪明方法。我的经验告诉我,使用地图可能比计算数字更快。可能是错误的,但是鉴于时间的限制,应该尝试这种尝试。
了解您的工具也有帮助,并且是开发人员技能的重要组成部分:不了解正则表达式,我要么花分配的三分钟时间搜索一个逗号分隔的列表,要么开始编写解析器来构建所需的数组。
记住,一个好的开发人员不是立即开始编码的人,而是知道在有更好的机会时如何避免编码的人。一些面试官会毫不犹豫地给您看似编码的作业,但几乎不需要任何编码。
示例3:完成应用程序开发
您需要在JavaScript中实现斐波那契序列。序列的长度在程序执行期间确定。该顺序遵循以下规则:
- 序列的前两个数字是0和1
- 每个后续数字是前两个数字的和。
例如:0、1、1、2、3、5、8、13、21、34、55、89。
该应用程序应显示为网页,允许用户通过输入字段指定序列的长度。
你有一个小时。
开始吧。
“示例序列非常有帮助,因为它可以让我进行大量的单元测试,以确保我的实现看起来不会完全错误。通常,我将Mocha用于node.js或将QUnit用于客户端JavaScript,但是在这里,为了简单起见,我将仅抛出一堆测试函数。
“我首先创建index.htm
和fib.js
归档。然后,我填写index.htm
了真正的简约代码,而不是与W3C兼容的代码(如果您也对我的HTML技能也感兴趣,我们可以稍后再讲)。”
<label>Length</label> <input id="length" value="15" />
<input id="compute" type="button" value="Compute" />
<div id="result" style="font-weight:bold;"></div>
<div id="tests"></div>
<script src="fib.js"></script>
“现在让我们编写一些代码,这些代码将调用斐波那契生成器函数并显示结果。”
fibonacci = (function () {
var compute,
init;
compute = function (length) {
// TODO: Implement Fibonacci sequence.
return [1, 2, 3];
};
init = function () {
var button = document.getElementById('compute');
button.addEventListener('onclick', function () {
var length = parseInt(document.getElementById('length').value, 10),
result;
console.log(
'Computing Fibonacci sequence of length ' + length + '.'
);
result = compute(length);
document.getElementById('result').innerText = result.join(', ');
});
};
return {
compute: compute,
init: init
};
}());
“是时候第一次运行代码了,……不起作用。没发生什么事。为什么?”
“好的,我忘fibonacci.init();
了最后。我添加了它,但是仍然没有任何反应,尽管它至少应该在控制台中显示消息。等待,对,不是onclick
,而是click
;我经常使用JQuery,以至于开始忘了纯JavaScript中事件的名称。”
“让我们添加一些测试。”
ensureAreEqual = function (expected, actual) {
var testResultsContainer = document.getElementById('tests');
testResultsContainer.innerText += (expected.equals(actual) ?
'.' :
('Actual [' + actual.join(', ') + '] is different from ' +
'expected [' + expected.join(', ') + '].'));
};
test = function () {
ensureAreEqual([0], compute(1));
};
“比较数组可能很棘手,所以我只是Array.prototype.equals
从此答案中复制粘贴 代码。”
“现在我们运行该应用程序,它将显示:”
实际[1、2、3]与预期[0]不同。
“鉴于我们return [1, 2, 3];
的斐波那契数列的实际实现(),该测试失败了,这是人们高度期望的。是时候改变这一点了。”
“从原始语句开始,斐波那契数列以开头[0, 1]
,因此compute
变为:”
compute = function (length) {
var fib = [0];
return fib;
};
“这使通过第一个测试成为可能,我们现在可以编写第二个测试。”
ensureAreEqual([0, 1], compute(2));
“它失败了,所以我们回到compute
并修改它。”
compute = function (length) {
var fib = [0, 1];
return length === 1 ? [0] : fib;
};
“现在,两项测试都通过了,现在该转向非边缘案例了。”
compute = function (length) {
var fib = [0, 1],
i,
next,
current = 1,
previous = 0;
for (i = 2; i < length; i += 1) {
next = current + previous;
previous = current;
current = next;
fib.push(next);
}
return length === 1 ? [0] : fib;
};
“这三个测试现在都通过了,除了对于较大的长度(例如100)而言,结果看起来不正确。为了正确地获得这些结果,我们应该使用任意精度库。还有一些需要改进的地方。例如,命名约定有时太糟糕了(是什么fib
?)。与HTML相关的JavaScript代码以及测试代码也应转到其他对象。另外,我还没有测试compute(0)
,也没有检查输入。”
结论
通过遍历示例,您可能会看到面试中期望的互动。并非一切都很顺利(一开始我犯了一些错误,这使我陷入了一个尴尬的境地,当我运行应用程序时什么也没有发生),并且如果我们必须支持较大的序列长度,最初的方法很la脚,但是我已经实现了证明:
- 我可以处理不同的问题,
- 我使用测试驱动的开发,斐波那契序列是一个极好的机会,
- 当源值得信赖时,我会复制粘贴代码,并且从头开始编写代码似乎极其复杂且容易出错,
- 我并不太依赖JQuery之类的库,
- 我选择了合适的范围:由于面试官想检查我的JavaScript技能,因此我不会浪费时间来编写完美而干净的HTML:不在这里花费时间可以花更多时间在编写单元测试上,
- 我知道何时完成并告诉我已完成,同时请记住,很多事情都不是完美的(例如
compute(0)
可能会失败,但对于演示来说并不重要)。
这正是面试官对您的期望。