簡單卻又復雜的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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM