简单却又复杂的FizzBuzz面试编程问题

     写这篇文章主要是因为偶然看到一篇关于stackoverflow公司的面经中提到了一个有趣的面试编程问题,如题所述:FizzBuzz问题。原文引用如下:

     “在一些公平的考验之后,我发现那些因为代码而抓狂的人不是为了庞大的项目,而是在细小的地方就缠不休。所以我开始研究这些问题,收集这些编程人员的特点 和归结成一类问题,取名为“FizzBuzz 问题”。 FizzBuzz问题是一种英国学校学生经常玩的游戏。举个“FizzBuzz 问题”的例子:

写一个程序打印1到100这些数字。但是遇到数字为3的倍数的时候,打印“Fizz”替代数字,5的倍数用“Buzz”代替,既是3的倍数又是5的倍数打印“FizzBuzz”。

大部分优秀的程序员都应该能在纸上轻易地把这个程序写出来,也就几分钟的事情。但你想知道一个令人震惊的事实吗?多数计算机科学专业的毕业生不会做这道题。我还见过一个自称是高级程序员的人做这道题,他居然花了10~15分钟。

Dan Kegel在招聘初级程序员的时候,也经历了类似的事情:令人惊讶的是,有相当一部分的应聘者(包括那些获得计算机科学专业的硕士或博士学位的人),当他们被要求完成一个基本的编程任务时,他们都通不过,因此面试失败。举例来说,我曾经碰到过一些毕业生,他们居然回答不出"写一个从1数到10的循环"或者"在16进制里F后面的数是什么"之类的问题。如果务实一点,我在面试中也碰到过很多应聘者,他们不会用递归去解决一个实际的问题。但这些都是基本的技能。如果他们不会,只能说明他们很可能根本就没写过程序。

      乍看这个问题的时候感觉题目叙述很清楚啊,思路也很简单啊,比现在很多公司用的字符串逆序,字符串空格替换啥的简单多了啊,为什么还会如此火地作为一个面试编程题?自己动手写了个,1分钟搞定,没毛病。然后怀着疑问就去百度了下,还真有各种论坛博客等网站都在讨论怎么写。然后看了下那些不屑一顾的编程爱好者们贴出来的代码,看完大家的代码后,我的内心是崩溃的,终于知道为什么这也能作为程序员们的面试编程题目了

  看到这里的你不妨也去写一写吧,说不定写的过程中也会发现联想起来很多有趣的事呢)。

  不知道为什么常逛CSDN的那些技术宅们,为何会给出这样奇葩的答案,再次刷新了我对CSDN的用户平均技术水平,下面把几种CSDN论坛里网友给出的答案并且在真实面试中很多人都容易犯的毛病提出来吧,希望即将面试中要手写代码的亲多留意下这些问题:

  

  大哥你这是用python吗,给个语言提示啊。而且这是要手动从1打印到100?说好的3和5的控制呢?再说python是不需要分号的啊,你开头加后面又不加是什么编码风格?

  

  真不知道这哥们儿又是什么心态?(注:这两个答案是最先回复的,而且还得到了分数!)从代码风格来看,我感觉是完全从上面那答案复制,然后把print改成了cout>>了,对,你没有看错!是>>而不是<<,我真想问问这哥们儿,你真学过C++没?而且先不说你们俩都没有实现题目的需求,别人python不写分号没毛病,你这最后一句不写就有点尴尬了啊。

  

  好吧,终于算是一个看起来比较正常的代码了,眼前一亮,好欣慰。可是!我随便带一个数15进去,发现输出完全不对啊?这个代码会输出Fizz-Buzz \n Fizz \n Fizz-Buzz \n Buzz啊?这只有if没有else的代码看起来还是不靠谱,好吧,这个人估计到了面试也会倒下...  

  嗯哼,这个代码还算不错,验证结果也是正确的。不过啊,难道没有代码规范意识?三目运算符“?:”在一条一句里用了三次也是蛮佩服的,但是如果是公司的线上代码写成这样会被人嫌弃得要死吧!真是印证了那句“***的裹脚布,又臭又长”

  

  一眼看过去,第一:不符合题意要求,明明要求的是如果是*的倍数,只输出单词即可,为何要自作主张输出数字加冒号?这是面试中的大忌讳,切记不可自以为是的修改了“用户需求”。第二:这明显是把特殊case处理了,普通case给直接漏掉了啊?结果自然就不对了

  

  哇,好工整,好想来句赞,可是......为什么是range(1,100)?你是对题意没理解清楚还是不知道range的具体用法呢?另外,其中三处continue实乃画蛇添足!

  

  看到第一句,就有点心累,又是范围问题,题目中明确说了是1~100的数字,怎么变成[0,100)区间了呢?而且中间有明显的冗余判断:如果进了else if(i%5--0)这个条件里,就不可能进入里面一层的if(i%3==0)好吧?

  

  我勒个去?我都开始怀疑这个人为何要加入CSDN了,如果题目突然换成1000,100000了,你也手算?

  

  哇,竟然看到了有人用js来提交,仔细一看。。顿时失望了。第一,还是范围问题。第二,思路倒是没问题啊,对倍数进行重新赋值,可是,那个len=15那里,为什么还是赋值为Fizz?题目没看清还是手抖了?另外,效率较低。

  

  经验证,这个代码可以满足需求,终于算是看到了一个能pass的代码了。不过,这个需要半个小时?有点接受不了。而且这代码格式,看了让人落泪,听了让人疯狂

  

  最后贴一个,这个实在是胆小精悍,乍一看还以为没实现,不过看起来不明觉厉,就去验证了下,发现!!!除了0也被包含进来(范围问题)之外,竟然完全正确,实在是python大法好啊!仔细看了下,如果真的面试中就写了这一句给面试官,并且搭配上准确的解释那也将是完美的通过面试节奏。这一句里面涉及到的知识点有:for in语法、range函数(另外,为什么不用xrange呢岂不更好)、[::]。将自己对这三个语法知识点的理解和延伸说说,将让面试官心服口服!


 

  当然,上面很多代码是很直接的硬伤,连基本需求都过不了,作为要去面试的人来说,这道题如果写不出满足基本需求的代码,感觉有点过分啊!

  不过我觉得如果想作为一个合格的工程师(好吧,如果你想称呼自己为程序员...开心就好),这个基本需求还远远不够,因为工作中的实际需求比这个不知道要复杂多少倍!

  从这题来说的话,需要说的点还有:拓展性效率问题。

  也许只从这100个数来看,对效率问题可能不会有什么要求,总是要遍历的嘛,而且就100个数,效率影响因子基本可忽略。但是如果把这个问题拓展到实际环境,这个100可能被瞬间变为100亿,同样这个过程也可能重复运行上亿次,这个时候,我们就不得不考虑效率问题了。

  对于拓展性,这里很简单,就是把那个magic number(100)拿出来当做函数的参数(面试中给的编程题都最好写成函数的形式,哪怕只是一段简短的代码!既然是个函数,就要注意函数参数和返回值问题等等),这样就可以根据实际情况来确定数据范围。

  效率的话,当然是冗余判断次数越少越好,充分利用已有条件来减少判断次数。 下面是以C语言为例的示例代码:

 1 void printFizzBuzz(int n=100)
 2 {
 3     for (int i = 1; i <= n; ++i)
 4     {
 5         if (i % 3 == 0)
 6         {
 7             if(i % 5 == 0)
 8                 printf("FizzBuzz\n");
 9             else
10                 printf("Fizz\n");
11         }
12         else if (i % 5 == 0)
13         {
14             printf("Buzz\n");
15         }
16         else
17         {
18             printf("%d\n", i);
19         }
20     }
21 }

  对于效率问题,这个代码中,每个数进来都只会判断两次并打印出结果。而对比上面贴出的CSDN网页们的答案,很多答案将会有更多次判断。

  其实问题可以再严肃一点:每个输出之间的间隔符题目中没有明确规定,但是不代表没有,上面有些答案中并没有输出分隔符,这也算是一个问题吧,上面我提供的这个代码中是以换行作为分隔的,如果是要以空格分隔,并且最后一个结果后面不加分隔呢?如果要每k个数用\n分隔,k个数之间用空格分隔呢?这些就变得稍微复杂了,更能考验面试者的严谨性、编码能力、编码风格和思维方式了。

  另外,对于擅长不同编程语言的人来说,可能会用不同的语言来实现,那么如果是你,你会用多少种较主流的语言来完整且正确的写出这个问题的答案呢?

  最后,我不得不承认,这真的是一个考验面试者的编程能力的好问题!


  本文经过分析CSDN相应帖子后整理得出,转载请注明出处-“闻波 博客园”:http://www.cnblogs.com/webary/p/6507413.html

 

posted @ 2017-03-06 13:34 闻波 阅读(...) 评论(...) 编辑 收藏
友情链接: