悠然乱弹:拉钩网FizzBuzzWhizz试题之悠然版解答

试题

?


1

2

3

4

5

6

7

你是一名体育老师,在某次课距离下课还有五分钟时,你决定搞一个游戏。此时有100名学生在上课。游戏的规则是:

 

1. 你首先说出三个不同的特殊数,要求必须是个位数,比如357

2. 让所有学生拍成一队,然后按顺序报数。

3. 学生报数时,如果所报数字是第一个特殊数(3)的倍数,那么不能说该数字,而要说Fizz;如果所报数字是第二个特殊数(5)的倍数,那么要说Buzz;如果所报数字是第三个特殊数(7)的倍数,那么要说Whizz。

4. 学生报数时,如果所报数字同时是两个特殊数的倍数情况下,也要特殊处理,比如第一个特殊数和第二个特殊数的倍数,那么不能说该数字,而是要说FizzBuzz, 以此类推。如果同时是三个特殊数的倍数,那么要说FizzBuzzWhizz。

5. 学生报数时,如果所报数字包含了第一个特殊数,那么也不能说该数字,而是要说相应的单词,比如本例中第一个特殊数是3,那么要报13的同学应该说Fizz。如果数字中包含了第一个特殊数,那么忽略规则3和规则4,比如要报35的同学只报Fizz,不报BuzzWhizz。

乱弹

据说是直接用来面试的,呵呵,很明显,写得少不是目标,写得快也不是目标,怎么样优雅的解决此问题还是重点。

如果用一个方法解决了此问题的同学,我可以负责任的说,基本上没有啥戏了。

悠然的方法不是最快的,悠然的方法也不是最小的,因此从这两个方面与悠然比较的,悠然承认落败了。

悠然主要从扩展性及代码的优雅性方面来做一下解答,也顺便普及一下设计方面的一些心得体会,与大家分享。

思路

此题明显是搞了一堆复杂的计算规则,来扰乱程序员的心灵,干扰程序员的思路,弄乱程序员的代码,出题之人是心怀叵测呀。但是抛开现象看本质,它就是让学生报数,然后在报数的时候要遵循一系列的规则。那么,很明显是可以按规则引擎的思路来解决的。(话外音:凡是有大量if语句,case语句的多都可以归到规则引擎范畴)。

简单的分析,可以把试题中的规则进行如下分类:

1.如果是包含第一个特殊数字的,直接读出拉倒

2.如果是能被其中几个特殊数字整除的,则要读出几个特殊的数字对应的文字

3.如果不是上面两种情况,就直接读出数字

OK,原来这么简单,那就开工了

代码

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

/**

 * Created by luoguo on 2014/5/6.

 */

public interface NumberReader extends Comparable<NumberReader>{

    /**

     * 返回处理优先级,优先级越高,越先执行

     *

     * @return

     */

    int getPriority();

 

    /**

     * 返回排它模式

     * 如果返回true,则自己执行过之后就结束

     * 如果返回false,则表示自己执行过之后,同优先级其它处理器还可以接着处理

     *

     * @return

     */

    boolean isExclusive();

 

    /**

     * 读数字

     *

     * @param number

     * @return 如果有读则返回true, 没有读则返回false

     */

    boolean read(int number);

}

设定了3个接口方法,一个返回优先级,一个返回是否是排它的,一个去读数字,如果有读过,则返回true,如果没有读过,就返回false、

另外,之所以继承了Comparable接口,是为了对规则进行排序。

为了避免后续的程序复制,因此搞一个抽象类:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

/**

 * Created by luoguo on 2014/5/6.

 */

public abstract class AbstractNumberReader implements NumberReader {

    private int priority;

    private boolean exclusive;

 

    public AbstractNumberReader(int priority, boolean exclusive) {

        this.priority = priority;

        this.exclusive = exclusive;

    }

 

    public int getPriority() {

        return priority;

    }

 

    public boolean isExclusive() {

        return exclusive;

    }

 

    public int compareTo(NumberReader numberReader) {

        if (priority > numberReader.getPriority()) {

            return -1;

        }

        if (priority < numberReader.getPriority()) {

            return 1;

        }

        return 0;

    }

}

上面的抽象类已经把复制的代码都写完了,接下来看实现类。

?


1

2

3

4

5

6

7

8

9

10

public class CommonNumberReader extends AbstractNumberReader {

    public CommonNumberReader() {

        super(0, true);

    }

 

    public boolean read(int number) {

        System.out.print(number);

        return true;

    }

}

普通的数字,其优先级为0,属于排它处理,不管3721,只要到我这里,我就一定会处理并返回true。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

/**

 * Created by luoguo on 2014/5/6.

 */

public class IncludeNumberReader extends AbstractNumberReader {

    private String title;

    private char num;

 

    public IncludeNumberReader(int num, String title) {

        super(2, true);

        this.num = (char) ('0' + num);

        this.title = title;

    }

 

    public boolean read(int number) {

        if (Integer.toString(number).indexOf(num) >= 0) {

            System.out.print(title);

            return true;

        }

        return false;

    }

}

包含数字时的处理,设定优先级为2,排它性为true,如果包含了对应的数字才处理。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

/**

 * Created by luoguo on 2014/5/6.

 */

public class MultipleNumberReader extends AbstractNumberReader {

    private String title;

    private int dividend;

 

    public MultipleNumberReader(int dividend, String title) {

        super(1, false);

        this.dividend = dividend;

        this.title = title;

    }

 

    public boolean read(int number) {

        if (number % dividend == 0) {

            System.out.print(title);

            return true;

        }

        return false;

    }

}

倍数处理器,它的优先级是1,是非排它的,只要是指定数的整数倍,就处理。

上面就写完了所有的规则。

下面是规则引擎了,呵呵,由于比较简单,没有抽象接口,直接就实现了。如果是复杂的,可能应该抽象成接口,使得引擎也可以进行调整。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

/**

 * Created by luoguo on 2014/5/6.

 */

public final class NumberReaderEngine {

    private List<NumberReader> numberReaders = new ArrayList<NumberReader>();

 

    public void add(NumberReader numberReader) {

        numberReaders.add(numberReader);

    }

 

    /**

     * 在调用readNumber之前必须调用sortNumberReader

     */

    public void sortNumberReader() {

        Collections.sort(numberReaders);

    }

 

    public void readNumber(int number) {

        executeReadNumber(number);

        System.out.println();

    }

 

    private void executeReadNumber(int number) {

        int readPriority = -1;

        for (NumberReader numberReader : numberReaders) {

            //如果已经有读过,且当前优先级与已经读过的优先级不同,则结束

            if (readPriority != -1 && numberReader.getPriority() != readPriority) {

                return;

            }

            boolean isRead = numberReader.read(number);

            if (isRead) {

                if (numberReader.isExclusive()) {

                    //如果是独占方式,且已读,则直接返回

                    return;

                } else {

                    readPriority = numberReader.getPriority();

                }

 

            }

        }

    }

}

引擎干的事情,很简单,就是添加规则,对规则进行排序,然后利用引擎对数字进行读出处理。

测试代码

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

/**

 * Created by luoguo on 2014/5/6.

 */

public class TestClass {

    public static void main(String[] args) {

        //简单起见,没有添加输入功能,而是直接在程序里初始化了

        NumberReaderEngine numberReaderEngine=new NumberReaderEngine();

        numberReaderEngine.add(new CommonNumberReader());

        numberReaderEngine.add(new IncludeNumberReader(3,"Fizz"));

        numberReaderEngine.add(new MultipleNumberReader(3,"Fizz"));

        numberReaderEngine.add(new MultipleNumberReader(5,"Buzz"));

        numberReaderEngine.add(new MultipleNumberReader(7,"Whizz"));

        numberReaderEngine.sortNumberReader();

        for(int i=1;i<100;i++){

           numberReaderEngine.readNumber(i);

        }

    }

}

测试代码很简单,就是添加一堆规则,然后读数字就好了

运行结果

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

1

2

Fizz

4

Buzz

Fizz

Whizz

8

Fizz

Buzz

11

Fizz

Fizz

Whizz

FizzBuzz

16

17

Fizz

19

Buzz

FizzWhizz

22

Fizz

Fizz

Buzz

26

Fizz

Whizz

29

Fizz

Fizz

Fizz

Fizz

Fizz

Fizz

Fizz

Fizz

Fizz

Fizz

Buzz

41

FizzWhizz

Fizz

44

FizzBuzz

46

47

Fizz

Whizz

Buzz

Fizz

52

Fizz

Fizz

Buzz

Whizz

Fizz

58

59

FizzBuzz

61

62

Fizz

64

Buzz

Fizz

67

68

Fizz

BuzzWhizz

71

Fizz

Fizz

74

FizzBuzz

76

Whizz

Fizz

79

Buzz

Fizz

82

Fizz

FizzWhizz

Buzz

86

Fizz

88

89

FizzBuzz

Whizz

92

Fizz

94

Buzz

Fizz

97

Whizz

Fizz

Buzz

代码行统计

从上面看到,总共的代码行数是122行,去掉15行测试代码行,7行package声明,刚好100行。

扩展性

从上面的代码可以看到,逻辑是可以方便的自由的增加的,比如,说,不仅是第一个特殊数字,第二个第三个特殊数字,也要用同样的逻辑,只要:

?


1

2

numberReaderEngine.add(new IncludeNumberReader(5,"Buzz"));

numberReaderEngine.add(new IncludeNumberReader(7,"Whizz"));

就可以了,不必修改计算逻辑。当然,也可以继续增加各种各样的逻辑。

总结

对于复杂的问题,要有抽丝剥茧的能力,仔细分析、认真设计,最后可以给出一个易于维护,易于扩展,易于理解,易于维护的解决方案。

想获得源码的同学,请到下面的路径:

http://git.oschina.net/tinyframework/FizzBuzzWhizz.git

时间: 2024-10-31 21:23:26

悠然乱弹:拉钩网FizzBuzzWhizz试题之悠然版解答的相关文章

悠然乱弹:螺旋矩阵和蛇型矩阵的悠然版实现

螺旋矩阵和蛇型矩阵,是两个比较有趣的矩阵,有许多的公司面试题中有出现,这两个题的答案也有许多种,简单问一下度娘,就各自有N种实现,来源也非常丰富,比如CSDN.ITEYE.等等,当然也包括著名的OSC,但是整体看下来,呵呵,比较顺眼的比较少,比较经典的就越发少了. 考虑到不同的语言有不同的语言特性,因此今天就只用Java来进行实现,看看螺旋矩阵和蛇型矩阵的悠然版实现,让我们的OSC也更加高大上一些,. 概念说明 什么是螺旋矩阵 螺旋矩阵是指一个呈螺旋状的矩阵,它的数字由第一行开始到右边不断变大,

网页转换-请问设计了一套笔试题(word2007版),如何转换成网页格式并具备倒计时功能?

问题描述 请问设计了一套笔试题(word2007版),如何转换成网页格式并具备倒计时功能? 我设计了一套人格测试题,都是选择题,用的是word07版,希望将答题时间限定在15分钟内,在候选人点击进去时便开始倒计时,咨询了一位IT朋友,她说要转换成网页格式并下一个插件,请教各位大神,应该如何做才能实现计划功能?谢谢! 解决方案 http://www.officezu.com/a/word/6203.html 解决方案二: 网页的话,js有很多第三方计时库

线程-JVM相关基础面试题--请大神解答

问题描述 JVM相关基础面试题--请大神解答 (单选)下列关于JVM说法,错误的是() A.JVM通过专门的线程实现内存的回收. B.使用java命令时,可以通过参数来设置分配JVM的内存大小. C.JRE包括JVM及Java核心类库. D.目前主流版本JVM通过纯解释的方式运行Java字节码. 为什么正确答案是D?B错在哪里了?请热心大神帮我看看 解决方案 下列关于JVM说法,**错误**的是() 问你的是错误的是,不是正确的是.JVM使用JIT编译器来提速,不是纯解释,别的都是对的.

jsp-关于JSP页面默认只有一个下拉选的内容!急求解答呀!

问题描述 关于JSP页面默认只有一个下拉选的内容!急求解答呀! function selectMedicalHealthInstitutions(){ var smhi = $('#medicalHealthInstitutions').val(); if(smhi=="1"){ $('#hosInputs').show(); $('#unitInputs').hide(); }else{ $('#unitInputs').show(); $('#hosInputs').hide()

悠然乱弹:挑战编程极限的问题终于有解了

问题的来历 在群里面一个小萝莉非要说拜我为师,呵呵,对于程序媛我一向--嗯嗯觉得程序不如人好看,再加上该名萝莉大学还没毕业,术语都多半没有听过,于是就想着拒绝,当时嘴一贱,就说了一句:你用一个For循环做个99表出来. 当然,这个对于小萝莉们来说,已经足够形成挑战了,但是对于群里的一众大佬们来说,自然是不在话下,3下5除二就搞定了.我又异想天开一下,如果不用判断语句,是不是也完成呢?粗想想是可以的,于是动手摆了几行代码,确实可以.于是就不断加码,不断增加新的完成条件,于是就形成了下面的问题,挑战

悠然乱弹:聊聊模块化

序言 熟悉了TINY相关开源内容的同学都有一个印象,那就是Tiny框架的目录分得非常细,比如Tiny工程的目录结构是下面的样子的: 比如TinyUiEnterprise项目的目录结构是这样的: 再比如,我们开源的软件开发过程管理软件的地目录结构是这样的: 有少许的人看了之后,深以为然,而更多的人看了之后却觉得莫名其妙.所以今天就乱弹一下模块化. 什么是模块化? 百度了一下,发现下面的说法非常经典,就此引用一下:模块化是一种处理复杂系统分解为更好的可管理模块的方式. 百度百科中,关于模块化设计是这

悠然乱弹:我的架构观

既然是乱弹,当然就不能全用正理推断,因此文中有文不对题的,思维混乱的都属正常范畴,大家谅解则个.  架构,是一个神秘也是一个普通的词汇. 曾几何时,君不见现在架构师就像雨后春笋似的,忽如一夜春风来,千树万树上面结的都是架构师,不管是招聘的,不管是应聘的,动辄就是资深架构师,高级架构师云云. 有的人说,架构是搞一堆时髦的大家不理解词汇,最好是一堆一堆的英文缩写,网上有的,网上没的,就象华为似的,任你是国内的国外的,没有缩写词词典管叫你寸步难行,然后再弄一大堆理论出来,然后架构就有了.  有的人说,

悠然乱弹:如何正确看待加入Tiny团队先从测试用例编写和文档编写开始?

有一个同学,问我一个问题:加入Tiny是否必须从写单元测试用例和文档作起? 此问题引发我诸多感触,故形成乱弹一篇. 作为一个新加入者,多看.少说,是正点.而这个时候,写写测试用例.文档,就是个不错的选择.这样入手比较容易,也比较容易体现水平. 可以说好的程序员,测试和文档都是写得好的.测试和文档一定写不好的,一定不是好的程序员.  同时,在看代码,写测试用例.写文档的过程中,还可以这样思考: 他为什么要这么设计?换成我,我会怎么设计?然后有相当一部分,会转化成:哦,原来是这个样子的!这个时候你进

拉钩网java笔试题分享_java

你是一名体育老师,在某次课距离下课还有五分钟时,你决定搞一个游戏.此时有100名学生在上课.游戏的规则是:1. 你首先说出三个不同的特殊数,要求必须是个位数,比如3.5.7.2. 让所有学生拍成一队,然后按顺序报数.3. 学生报数时,如果所报数字是第一个特殊数(3)的倍数,那么不能说该数字,而要说Fizz:如果所报数字是第二个特殊数(5)的倍数,那么要说Buzz:如果所报数字是第三个特殊数(7)的倍数,那么要说Whizz.4. 学生报数时,如果所报数字同时是两个特殊数的倍数情况下,也要特殊处理,