Programming

ちょっと意地悪なFizzBuzz問題

 Author:fumiyasac

プログラマの採用試験でよく出てくるものに「FizzBuzz問題」があります。そうです、あの「3の倍数の時にはFizz」と「5の倍数の時にはBuzz」と「15の倍数の時にはFizzBuzz」を出力するというオーソドックスなやつです。
しかしながら、こんなFizzBuzz問題だったらどうやって対処しますか?

1. 問題を見てみよう

いつもの「Fizzbuzz問題」とどこが違うかよく見てみましょう。

問題:
1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。
※ただし、剰余の計算を用いてはならない。

いつもの「FizzBuzz問題」とは違い、剰余(余り)を用いての計算が使えないということです。ほとんどの場合では剰余の計算を用いたプログラムを書くのですが、このような場合は以下の点に着目してあげます。

2. 整数の性質に注目する

3の倍数と5の倍数の判定法を使います。少し数学的な説明が続くので、苦手意識があった方には恐縮ですがお付き合いください。
数学の問題でも昔学習したかと思いますが、3の倍数と5の倍数にはこのような性質があります。

  • (3の倍数)それぞれの位の和が3の倍数である
  • (5の倍数)一の位が0または5である

3. 5の倍数の判定

まずは5の倍数の判定はsubstr関数などを駆使して一の位の数値を抜き出してあげれば、いけそうな感じがしそうですね。

  1. <?php
  2. function is_five($num){
  3.   $val = (string)$num;
  4.   $result = (intval)substr($val, -1, 1);
  5.   if($result == 5 || $result == 0){
  6.     return true;
  7.   }else{
  8.     return false;
  9.   }
  10. }
  11. ?>

さて問題は3の倍数です。余りが使えない以上、和の判定を他のやり方を考えないといけないです。そこで3の倍数は和の最大値に注目します。

4. 3の倍数はそれぞれの桁数の和を考える

桁数の和が最大となるのは99のときなので、
「1から100までのそれぞれの位の和の最大値は18」
であることがわかります。
これを使えば、それぞれの位の和が3の倍数になるパターンは3,6,9,12,15,18となるのでこの性質を利用した条件分岐をすればいいと思います。

  1. <?php
  2. function is_three($num){
  3.   $val = (string)$num;
  4.   $result1 = (intval)substr($val, -1, 1);
  5.   $result2 = (intval)substr($val, -2, 1);
  6.   $result3 = (intval)substr($val, -3, 1);
  7.   $result = $result1 + $result2 + $result3;
  8.    if($result == 3 || $result == 6 || $result == 9 || $result == 12 || $result == 15 || $result == 18){
  9.     return true;
  10.   }else{
  11.     return false;
  12.   }
  13. }
  14. ?>

この2つの関数を利用して、今までのFizzBuzz問題のように書いてあげればOKです。

5. 回答例(PHP)

※かなり甘いところがあると思いますが、そこはご容赦下さい。

  1. <?php
  2. for($cnt=1; $cnt<=100; $cnt++){
  3.   if(is_three($cnt) == true) print "Fizz";
  4.   if(is_five($cnt) == true) print "Buzz";
  5.   if(is_five($cnt) == false && is_three($cnt) == false) print $cnt;
  6.   print "<br>";
  7. }
  8. ?>

今回はPHPでささっと書きましたが、他のプログラムないしはもっと効率的な書き方があればぜひ教えてくださいね!