zoukankan      html  css  js  c++  java
  • 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:如果输入不是数字,而是字符串,应该如何处理?

    完整源码下载:http://files.cnblogs.com/LoveJenny/FizzBuzz.7z

  • 相关阅读:
    诸神之眼-Nmap(精版,更新中。。。)
    workerman-chat聊天室
    Mysql记录事本
    网站标题、描述、关键词怎么设置?
    什么是谷歌SEO?
    图片加载之性能优化
    前端实现图片懒加载(lazyload)的两种方式
    HTML`CSS_网站页面不同浏览器兼容性问题解决
    从输入url到显示页面,都经历了什么
    什么是mvvm mvc是什么区别 原理
  • 原文地址:https://www.cnblogs.com/LoveJenny/p/3706459.html
Copyright © 2011-2022 走看看