今天早上到現在看到了3篇關於FizzBuzzWhizz的問題,第一篇是@程序媛想事兒(Alexia)【最難面試的IT公司之ThoughtWorks代碼挑戰——FizzBuzzWhizz游戲】其實題目不難,大家解法也都能實現,可大家比拼的都是算法問題,但如此簡單的題目真的只是簡單的算法嗎?我不這么認為,我們先來看看題目吧:
你是一名體育老師,在某次課距離下課還有五分鍾時,你決定搞一個游戲。此時有100名學生在上課。游戲的規則是:
1. 你首先說出三個不同的特殊數,要求必須是個位數,比如3、5、7。
2. 讓所有學生拍成一隊,然后按順序報數。
3. 學生報數時,如果所報數字是第一個特殊數(3)的倍數,那么不能說該數字,而要說Fizz;如果所報數字是第二個特殊數(5)的倍數,那么要說Buzz;如果所報數字是第三個特殊數(7)的倍數,那么要說Whizz。
4. 學生報數時,如果所報數字同時是兩個特殊數的倍數情況下,也要特殊處理,比如第一個特殊數和第二個特殊數的倍數,那么不能說該數字,而是要說FizzBuzz, 以此類推。如果同時是三個特殊數的倍數,那么要說FizzBuzzWhizz。
5. 學生報數時,如果所報數字包含了第一個特殊數,那么也不能說該數字,而是要說相應的單詞,比如本例中第一個特殊數是3,那么要報13的同學應該說Fizz。如果數字中包含了第一個特殊數,那么忽略規則3和規則4,比如要報35的同學只報Fizz,不報BuzzWhizz。
初看題目,很多人會以為就是求個算法,其實不然,說白了算法很簡單,先判斷第5規則,再判斷第3,第4,其實3和4可以利用字符串拼接,無需重復來進行判斷。我們逐一來看題目吧。
1、你首先說出三個不同的特殊數,要求必須是個位數,比如3、5、7
這是我們的輸入,3個特殊數,必須為個位數。因為是根據報數,肯定n > 0,我們的特殊數m 也肯定必須>0,根據題目3,4,我覺得可以把1排除在外,當然也可以包含在其中,每個人理解不一樣吧。因為是個位數,所以1<m<10。因為對m有要求,所以必須對我們3個特殊數進行一個驗證。
2、讓所有學生拍成一隊,然后按順序報數
這個簡單,循環到100,我看到有朋友用了for(int i = 1;i<101;i++) ,不是不可以,但題目寫了100個學生,為何你要去<101呢?<=100就可以了,盡量符合題目。
3、學生報數時,如果所報數字是第一個特殊數(3)的倍數,那么不能說該數字,而要說Fizz;如果所報數字是第二個特殊數(5)的倍數,那么要說Buzz;如果所報數字是第三個特殊數(7)的倍數,那么要說Whizz。
4. 學生報數時,如果所報數字同時是兩個特殊數的倍數情況下,也要特殊處理,比如第一個特殊數和第二個特殊數的倍數,那么不能說該數字,而是要說FizzBuzz, 以此類推。如果同時是三個特殊數的倍數,那么要說FizzBuzzWhizz。
3和4的規則可以通過字符串拼接,合並在一起
if (m % num1 == 0) str += “Fizz”;
if (m % num2 == 0) str += “Buzz”;
if (m % num3 == 0) str += “Whizz”;
這些都是個人喜愛問題,你要一條條去驗證判斷,也沒什么問題。
5、學生報數時,如果所報數字包含了第一個特殊數,那么也不能說該數字,而是要說相應的單詞,比如本例中第一個特殊數是3,那么要報13的同學應該說Fizz。如果數字中包含了第一個特殊數,那么忽略規則3和規則4,比如要報35的同學只報Fizz,不報BuzzWhizz。
這條規則很特殊,所以我們的計算必須以if(5)else(3,4)進行,5的權重最高。
說完了規則,來看下其他的要求:
代碼要求:
1,語言不限,Java, C#, Ruby, C++, Js, Python, Scala, objective-C統統可以,小語種也沒問題,只要你擅長;
2,強烈建議寫單元測試;
3,請展示出你超贊的面向對象/函數式編程功底;
4,建議盡量減少圈復雜度;
5,請提交可運行的代碼,及相關構建腳本/說明文檔(代碼運行平台和環境);
2-4的要求非常重要,因為這是區別程序員級別的一個標准。測試代碼盡量全面。
我對題目的做法
看到題目的時候,活動結束了,也沒想細作,只能說個大概。我使用的是C#,使用的是面向對象的方法。我設計了一個Student類
public class Student { private int Id { get; set; } private IRule Rule { get; set; } public Student(int id, IRule rule) { Id = id; Rule = rule; } public void Say() { Console.WriteLine(Rule.RuleResult(Id)); } }
100個學生,說明有100個對象,id為其所需要報的數,IRule則是其核心算法,解耦其算法,以免項目中會有算法變動。
public interface IRule { string RuleResult(int number); }
如何實現IRule,則很簡單了,這里說下第5個規則,如果含有第一個特殊數,比如第一個特殊數是3,則13,31,35都只報“Fizz”,第一篇的樓主用了indexof,把所需報的數變成了字符串,然后查找,不是不可,但你懂得,裝箱拆箱不說,把數字變成了字符串就有點不符合題意了。我們可以使用加減的方法來進行判斷。
13,23,33,43:n % 10 – m = 0
31,32,33,34: n - (m * 10) >= 0 && n –(m*10) < 10
規則3,4,利用字符串的拼接就可實現,大致的實現為:
if (number % Number_1 == 0) { result += Num_Result_1; } if (number % Number_2 == 0) { result += Num_Result_2; } if (number % Number_3 == 0) { result += Num_Result_3; }
我的實現如下:
public string RuleResult(int number) { var result = String.Empty; var isRuled = false; if ((number % 10 - Number_1) == 0 || (number - (Number_1 * 10) >= 0 && number - (Number_1 * 10) < 10)) { isRuled = true; result = Num_Result_1; } else { if (number % Number_1 == 0) { result += Num_Result_1; isRuled = true; } if (number % Number_2 == 0) { result += Num_Result_2; isRuled = true; } if (number % Number_3 == 0) { result += Num_Result_3; isRuled = true; } } if (!isRuled) { result = number.ToString(); } return result; }
在不符合規則的情況下,返回number.ToString();
開始報數:
IRule role = new FBWRule(numbers); for (var i = 1; i <= 100; i++) { var student = new Student(i, role); student.Say(); }
接下來就是寫單元測試,我們只要針對IRule進行測試即可
[Fact] public void RuleTest() { IRule rule = new FBWRule(3, 5, 7); Assert.Equal("Fizz", rule.RuleResult(30)); Assert.Equal("Fizz", rule.RuleResult(35)); Assert.Equal("FizzBuzz", rule.RuleResult(15)); Assert.Equal("FizzBuzz", rule.RuleResult(45)); Assert.Equal("BuzzWhizz", rule.RuleResult(70)); }
寫在最后
今天看到“ThoughtWorks”最難面試題,看了以后才發覺,很簡單,但就是這么簡單的題目,回答的答案都各有千秋,我相信考的不僅僅是算法,在代碼中,思路中都能體現一個人的思想、行為,相信這是面試的關鍵吧。
剛試了下還能提交代碼,寫出來的目的也想看看的想法,接受任何批評和指點,謝謝。