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,如需转载请自行联系原作者
目录
相关文章
|
2月前
|
Java 开发者
Java 编程风格与规范:跟上时代热点,打造高质量代码,为开发者梦想保驾护航
【8月更文挑战第30天】本文强调了Java编程中代码质量和可维护性的重要性,详细介绍了命名规范、代码格式和注释的最佳实践,如使用描述性的命名、适当的缩进及空行,以及关键代码部分的注释说明,同时还提供了避免魔法值和减少代码重复的建议与示例,帮助提升团队协作效率和项目长期发展。
43 2
|
5月前
|
人工智能 安全 Java
【专栏】Java与WebAssembly将在不同场景共存互补,共同推动信息技术发展
【4月更文挑战第27天】本文探讨了编程语言的演进,从Java的辉煌及其在面对云计算、微服务等新需求时的挑战,到新兴技术如WebAssembly的崛起。WebAssembly以其高效性能、跨平台支持和与Web技术的融合,为编程语言带来新可能。未来趋势包括性能优化、多范式融合、与AI等技术结合及提升开发者体验。Java与WebAssembly将在不同场景共存互补,共同推动信息技术发展。关注新技术,以应对未来编程语言的挑战和机遇。
93 2
|
5月前
|
负载均衡 Java 数据库连接
Java从入门到精通:4.2.2学习新技术与框架——不断扩展自己的知识面,跟上技术的发展趋势
Java从入门到精通:4.2.2学习新技术与框架——不断扩展自己的知识面,跟上技术的发展趋势
|
Web App开发 JavaScript 前端开发
挑战“三大框架”的解决方案
Svelte 是一个轻量级的前端框架,旨在帮助开发者构建高效、交互式的Web应用程序。它有着非常高的性能和可靠性,并且不需要额外的运行时库来支持,将所有代码都编译为非常优化的纯JavaScript代码。这意味着您可以获得更快的加载速度和更流畅的用户体验,从而让您的网站或应用程序看起来更加专业和出色。本篇文章将对Svelte的主要特点和使用案例进行详细介绍,同时提供一些实用的技巧,帮助你更好地利用Svelte进行开发和构建交互式的Web应用程序。
11044 1
挑战“三大框架”的解决方案
|
NoSQL Java 关系型数据库
Java圣经!互联网寒冬的应对之法尽在其中
从去年12月份开始到今天,这个互联网寒冬已经持续了将近一年了,其实现在不仅是大厂在裁员,有很多中小厂也已经在裁员了,而且程序猿做为中高收入的人群,有很多人背负了房贷、车贷等等,需要养孩子,其实我们才是被资本割的最狠的一批韭菜!
|
自动驾驶 Java 大数据
为什么学Java?五大理由助你起航!
打开一切科学的钥匙都毫无异议地是问号,我们大部分的伟大发现都应当归功于如何?而生活的智慧大概就在于逢事都问个为什么?
为什么学Java?五大理由助你起航!
|
自然语言处理 Oracle JavaScript
2014年Java值得期待的五大理由
如果你还在为Oracle收购Sun公司给Java社区的变化所纠结,请站在Oracle的角度替它想想吧。2013年大部分时间里,Oracle都在与遗留的Java安全问题作战,我们感觉这些安全漏洞仍然会是2014年大家关注的热点。尽管如此,还是希望新年里Java会发展的更好。下面是我们给出的未来12个月热点提示。
183 0
2014年Java值得期待的五大理由
|
前端开发 Dubbo JavaScript
Java 程序员必备的 15 个框架,前 3 个地位无可动摇!
Java 程序员方向太多,且不说移动开发、大数据、区块链、人工智能这些,大部分 Java 程序员都是 Java Web/后端开发。那作为一名 Java Web 开发程序员必须需要熟悉哪些框架呢?
|
弹性计算 安全 架构师
2020年Java工程师就业前景分析
Java属于编程语言的核心语言,很多公司都在用Java,Java语言开发优势显著稳定性好,在服务器端Java发挥高性能、安全稳健的特性。
1347 0
|
Java 微服务 开发者
可能是国内第一篇全面解读 Java 现状及趋势的文章
作者 | 张晓楠 Dragonwell JDK 最新版本 8.1.1-GA 发布,包括全新特性和更新! 导读:InfoQ 发布《2019 中国 Java 发展趋势报告》,反映 Java 在中国发展的独特性,同时也希望大家对 Java 有一个正确的认识。
15379 0