ThoughtWorks代码挑战——FizzBuzzWhizz
很久没发表过文章了,今天看到一篇文章 最难面试的IT公司之ThoughtWorks代码挑战——FizzBuzzWhizz游戏(C#解法)
看到LZ的2B青年代码,实在是惨不忍睹,故写篇文章来探讨下这类问题的一般思考。
原题:
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。
一道看似简单的题目,其实并没有那么简单,如果你直接写的话,那估计就是:
if, if , else if , if , for, [0] [1] [2]….
我们来理解下这道题:
1. 你首先说出三个不同的特殊数,要求必须是个位数,比如3、5、7。
不同的三个数,必须是个位数,这些都是验证条件,你注意到了吗?
2. 让所有学生拍成一队,然后按顺序报数。
生成顺序的数字。
3. 学生报数时,如果所报数字是第一个特殊数(3)的倍数,那么不能说该数字,而要说Fizz;如果所报数字是第二个特殊数(5)的倍数,那么要说Buzz;如果所报数字是第三个特殊数(7)的倍数,那么要说Whizz。
规则:如果是某个特殊数的倍数,输出对应的值,否则输出数字。
4. 学生报数时,如果所报数字同时是两个特殊数的倍数情况下,也要特殊处理,比如第一个特殊数和第二个特殊数的倍数,那么不能说该数字,而是要说FizzBuzz, 以此类推。如果同时是三个特殊数的倍数,那么要说FizzBuzzWhizz。
规则:如果是多个特殊数的倍数,输出所有的对应值。
5. 学生报数时,如果所报数字包含了第一个特殊数,那么也不能说该数字,而是要说相应的单词,比如本例中第一个特殊数是3,那么要报13的同学应该说Fizz。如果数字中包含了第一个特殊数,那么忽略规则3和规则4,比如要报35的同学只报Fizz,不报BuzzWhizz。
规则:如果包含第一个特殊数字,则只输出第一个特殊数字所对应的值。
OK,思考下我们该怎样做?。。
我们来抽象的理解下题目: “给你输入一堆数字,然后你根据一定的规则进行parse,然后输出parse 的结果。”
所以这道题目想考察的是你如何定义这些规则,如何应用这些规则,该如何parse呢?
让我们看下规则Rule:
Rule,有优先级,然后可以对输入进行Parse,然后Parse又需要一个对应的字典。
所以Rule 像这样:
abstract class Rule{public abstract int Priority { get; }public Dictionary<int, string> SpecialDictionary { get; set; }public Rule(Dictionary<int, string> specialDictionary){this.SpecialDictionary = specialDictionary;}public bool ParseNum(int num, ref string result){if ((SpecialDictionary != null) && (SpecialDictionary.Count > 0)){return ParseNumCore(num, ref result);}else{return false;}}protected abstract bool ParseNumCore(int num, ref string result);}
接着Rule3: 如果是某个特殊数的倍数,输出对应的值,否则输出数字,输出数字我放到最外层去处理了,当然如果需要也可以写个Rule2.
class Rule3 : Rule{public Rule3(Dictionary<int, string> specialDictionary): base(specialDictionary){}public override int Priority{get { return 3; }}protected override bool ParseNumCore(int num, ref string result){foreach (var special in SpecialDictionary){if (num % special.Key == 0){result = special.Value;return true;}}return false;}}
Rule4:如果是多个特殊数的倍数,输出所有的对应值。
class Rule4 : Rule{public Rule4(Dictionary<int, string> specialDictionary): base(specialDictionary){}public override int Priority{get { return 4; }}protected override bool ParseNumCore(int num, ref string result){List<string> matches = new List<string>();foreach (var special in SpecialDictionary){if (num % special.Key == 0){matches.Add(special.Value);}}if (matches.Count > 1){result = string.Join("", matches);return true;}else{return false;}}}
Rule5:如果包含第一个特殊数字,则只输出第一个特殊数字所对应的值。
class Rule5 : Rule{public Rule5(Dictionary<int, string> specialDictionary): base(specialDictionary){}public override int Priority{get { return 5; }}protected override bool ParseNumCore(int num, ref string result){if (SpecialDictionary.Count > 0){var firstSpecial = SpecialDictionary.First();if (num.ToString().Contains(firstSpecial.Key.ToString())){result = firstSpecial.Value;return true;}}return false;}}
接下来:最重要的就是Parse 逻辑了,想一想应该怎样调用这些Rule呢(visitor ?):
foreach (var student in studentNums){string parseResult = student.ToString();foreach (Rule rule in rules){if (rule.ParseNum(student, ref parseResult)){break;}}Console.WriteLine(parseResult);}
下面是完整的代码:
private static void FizzBuzz(){bool isValidInput = false;do{Console.WriteLine("please input three numbers which is units digit, use ',' division ");string[] inputNums = Console.ReadLine().Split(',');if (ValidSpecialInput(inputNums)){isValidInput = true;// create special dictionary to parse the students nums.Dictionary<int, string> special = new Dictionary<int, string>();special.Add(Int32.Parse(inputNums[0]), "Fizz");special.Add(Int32.Parse(inputNums[1]), "Buzz");special.Add(Int32.Parse(inputNums[2]), "Whizz");// get students nums.int studentsCount = 100;var studentNums = Enumerable.Range(1, studentsCount);// create rules to parse.var rules = new List<Rule>() { new Rule5(special),new Rule4(special), new Rule3(special), }.OrderByDescending(r => r.Priority);// parse logic.foreach (var student in studentNums){string parseResult = student.ToString();foreach (Rule rule in rules){if (rule.ParseNum(student, ref parseResult)){break;}}Console.WriteLine(parseResult);}Console.ReadLine();}else{Console.WriteLine("the input is not valid.");}}while (isValidInput == false);}private static bool ValidSpecialInput(string[] specialInputs){bool result = false;if (specialInputs.Length == 3){return specialInputs.All(input =>{int num = 0;return Int32.TryParse(input, out num) && (num > 0) && (num < 10);});}return result;}
一些后续思考:
1:如果输入的不是三个,而是4个,5个 special, 应该怎么改?
2:如果学生数量不是100个,是1000个?
3:如果有限考虑Rule3,然后是Rule4,Rule5,应该怎么改?
4:如果还有另一个限制条件:比如如果数字是素数,把对应的值按反序输出,如何处理?
5:如果输入不是数字,而是字符串,应该如何处理?
本文转自LoveJenny博客园博客,原文链接:http://www.cnblogs.com/LoveJenny/p/3706459.html,如需转载请自行联系原作者 与50位技术专家面对面20年技术见证,附赠技术全景图
总结
以上是生活随笔为你收集整理的ThoughtWorks代码挑战——FizzBuzzWhizz的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 使用Varnish加速Web
- 下一篇: LeakCanary: 让内存泄露无所遁