Oracle首席工程师:技术面试中,怎样的问题才是好问题?( 六 )


候选人:……(意识到在某些情况下 , 有很多用户拥有相同的积分 , 这时时间复杂度会退化)
面试官:那样的话 , 你怎么优化?
候选人:数组的元素除了记录当前积分 , 还记录有多少个用户具有这个积分 , 从而消除相同积分的重复元素……
面试官:很好 , 可这个方法会带来一个问题 , 你能想到吗?
候选人:对了 , 如果积分变化以后 , 新的积分是没有出现过的 , 那么添加到数组里 , 就是一个新元素 , 于是所有比它小的积分全部都要向后移动一个单位 。
面试官:非常好 , 那么你怎么优化?
候选人:如果使用链表来代替数组就可以避免这个问题 , (突然意识到)可是链表我就没法二分查找了……
面试官:没错 , 那什么样的数据结构和链表在这方面具有一定相似性 , 又能够具备二分查找相似的时间复杂度?
候选人:……(这一步能回答出来答案就很多了 , 很多都是很不错的思路 , 比如有用跳表的 , 有用二叉搜索树的等等)
这只是一个简化了的片段 , 实际的沟通的内容远比这部分内容多 , 但是从中也依然可以管中窥豹 , 看出问题解决的过程是怎样逐步推进的 。
如果你对这个问题本身感兴趣的话 , 可以参阅一下 《排行榜算法设计实现比较》和 《海量用户积分排名算法》这两篇文章 , 它们讨论了其中的几个思路;另外 , 我以前在这篇文章里也简单讨论了其中的一个思路 。
从这里也可以看出 , 无论是从实际问题细化到软件问题 , 还是求解这个软件问题 , 都存在着多条通往罗马的道路 , 看起来很美好 , 但这样的问题设计和面试把控并不容易 。
既然大家都是软件工程师 , 是未来有可能一起工作的工程师 , 面试官的能力和可能就和候选人接近 。 于是 , 为了保证面试的效果 , 就一定要精心准备这样的问题 , 而不能指望随机和临场想出来一个 “好” 的问题提问 。
3、围绕问题的解决要完整
这个问题的分析、讨论和解答过程要完整 。 对 , 其实这一点说的已经不是问题本身了 , 而是攻克这个问题的过程了 。
这指的是整个过程要努力让候选人能够抵达 “踮踮脚能够到” 的难度 , 并且能够完成从确认、分析、讨论、编码、验证和改进等一个过程 。 这会让整个面试显得完整 , 同时带来了两大好处:

  • 对于面试官来讲 , 这样一个完整的过程 , 可以更全面地考察候选人 , 避免陷入视角过窄和一叶障目的情境 。 同时 , “踮踮脚能够到” 的难度 , 又可以给整个考察的进程具备较为合理的预期 。
  • 对于候选人来讲 , 心态可以得到一定程度的平复 , 不沮丧 , 能够 “完整地” 面试完一轮 , 能够收获信心 。 别忘了 , 面试是双向的 , 给候选人一个良好的印象是很重要的 。
前文我举的这个将问题从模糊到逐步清晰化的这个例子 , 就是一个需要面试官根据候选人情况动态调整的例子 。 在候选人能够经过思考而快速推进问题解决进展的时候 , 要让出主动权 , 以被动回答和鼓励为主;但在候选人卡壳的时候 , 要夺回主动权 , 及时给出提示和引导 。
在落到数据结构和算法上面的时候 , 极少有候选人能够在叙述思路的时候直接给出最优解的 。 这时候 , 如果时间充裕 , 特别是在候选人进展非常顺利的时候 , 可以不断提示、追问以要求 “代码前优化” , 一步一步优化到他/她的问题解决的能力边界 , 这就是其中的一个探寻其 “踮踮脚能够到” 的这个问题解决能力之边界的一个办法 。
但这个过程的前提是 , 一定要给编码留足时间 。 当然 , 如果候选人不能在限定时间内给出清晰的优化后思路 , 那不妨就退一步到原先那个算法角度不那么 “好” , 但是思路清晰的解法上 , 并落实到代码上 。
比方说 , 对于前文所述的那个流量控制的问题 , 候选人在还有半个小时的时候就想到了使用一个时间复杂度为 O(N) 的解 , 而面试官认为时间还比较充裕 , 那就可以尝试挑战一下候选人 “能否再优化一下复杂度” 。