ubichupas.net

俺はFizzBuzz問題を解ける方のプログラマなんだぜ

プログラマの採用試験において、まず簡単なプログラムを短時間で紙に書かせてみることで能力を計り、 面接の手間を省いてしまおうというアイディアがあるのだそうだ。 (((( ;゚Д゚)))ガクガクブルブル

■ FizzBuzz問題 (制限時間2分) 1から100までの数をプリントするプログラムを書け。 ただし3の倍数のときは数の代わりに「Fizz」と、 5の倍数のときは「Buzz」とプリントし、 3と5両方の倍数の場合には「FizzBuzz」とプリントすること。

さて自分が採用面接でこの問題を出されたらどうなるか考えてみました。

面接官「この紙に書いてあるプログラムを書いてください」
俺「(゚Д゚)ハァ?」 ←間違いなく第一声はコレ。
俺「下の余白に書けばいいんですね?」
面接官「はい」
俺「・・・はいはい」 ←問題文を読んでる最中に絶対言う。

fizzbuzz1.cs
for (int i = 1; i <= 100; i++)
{
  System.Console.WriteLine("{0}", i);
}

まずサラサラっと大枠を書きあげます。 c⌒っ*゚∀゚)っφサラサラ
※ここではC#で書いてますけど、脳内は基本C言語です。

fizzbuzz2.cs
for (int i = 1; i <= 100; i++)
{
  if (i % 3 == 0)
     System.Console.WriteLine("Fizz");
  else if (i % 5 == 0)
     System.Console.WriteLine("Buzz");
  else if (i % 3 == 0 && i % 5 == 0)
     System.Console.WriteLine("FizzBuzz");
  else
     System.Console.WriteLine("{0}", i);
}

次に問題文を読みながらif文を書き足していきます。 ここまででおよそ1分でしょうか。 (゚Д゚)y─┛~~ 上記のプログラムを頭の中で走らせると、"FizzBuzz"まで辿り着かずに"Fizz"が出力されることに気付くので訂正します。 Σ(゚д゚lll)アブネ

fizzbuzz3.cs
for (int i = 1; i <= 100; i++)
{
  if (i % 3 == 0 && i % 5 == 0)
     System.Console.WriteLine("FizzBuzz");
  else if (i % 3 == 0)
     System.Console.WriteLine("Fizz");
  else if (i % 5 == 0)
     System.Console.WriteLine("Buzz");
  else
     System.Console.WriteLine("{0}", i);
}

これでひとまず完成。 時間はまだ残ってるでしょうから、実行できるよう体裁を整えつつ「何か引っ掛けでもあるんじゃないか?」と疑いの目を向けてみることにします。 (¬_¬)・・・

fizzbuzz4.cs
class FizzBuzz
{
  public static void Main()
  {
    for (int i = 1; i <= 100; i++)
    {
      if (i % 15 == 0)  // if(i % 3 == 0 && i % 5 == 0)と同義
         System.Console.WriteLine("FizzBuzz");
      else if (i % 3 == 0)
         System.Console.WriteLine("Fizz");
      else if (i % 5 == 0)
         System.Console.WriteLine("Buzz");
      else
         System.Console.WriteLine("{0}", i);
    }
  }
}

できました。∩( ・ω・)∩ ばんじゃーい
ここで「3の倍数かつ5の倍数って15の倍数ってことじゃん」と2分以内に気付くのはたぶん無理かな。 でも気付かなくても何ら問題ないね。 つかむしろ蛇足でしょう。 ( ゚д゚)、ペッ
問題文(仕様)に書かれている数値は「1」「100」「3」「5」だけですから、 「15」を持ちだすなら根拠をコメントに記載しなければなりません。 もしそれをしないプログラマに出会ったら、そいつの履歴書にインテリ馬鹿とコメントしてあげてください。

1行縛り(ワンライナー)

ときにインテリ馬鹿より迷惑な存在となるのがギーク。 もう貴方には誰もついていけません。 ( ´∀`)σ)∀`)

fizzbuzz5.cs
class FizzBuzz
{
  public static void Main()
  {
    for (int i = 1; i <= 100; i++)
     System.Console.WriteLine(
         (i % 15 == 0 ? "FizzBuzz" :
          i %  3 == 0 ? "Fizz" :
          i %  5 == 0 ? "Buzz" :
          "{0}"), i);
  }
}

基本的に「1行で書け=三項演算子を使え」なので、 素直にif文を三項演算子に置き換えてやれば1行のプログラムになります。 三項演算子は「?」がTHENで「:」がELSEと覚えておくと良いでしょう。 (・∀・)カンタン!!

剰余を用いない縛り

倍数とかn回毎にと言われたら殆どのプログラマが%を使うでしょう。 だから敢えて%を使うなという嫌な縛り。 これを2分以内に解くのはシンドイですね。

fizzbuzz6.cs
class FizzBuzz
{
  public static void Main()
  {
    int c3 = 3;
    int c5 = 5;

    for (int i = 1; i <= 100; i++)
    {
      if (i == c3 && i == c5)
      {
         System.Console.WriteLine("FizzBuzz");
         c3 += 3;
         c5 += 5;
      }
      else if (i == c3)
      {
         System.Console.WriteLine("Fizz");
         c3 += 3;
      }
      else if (i == c5)
      {
         System.Console.WriteLine("Buzz");
         c5 += 5;
      }
      else
         System.Console.WriteLine("{0}", i);
    }
  }
}

掛け算は足し算をn回やればいい理論でクリアしました。 「変数を増やさないで何とか・・・」などと考えてしまったら時間切れコースです。

分岐を用いない縛り

分岐を無くせば処理が速くなるとか何とか。 高齢プログラマに多いですよね、頼まれなくても関数ポインタとか使いだす人。 配列の初期化が遥か彼方で行われいない限り何も言いますまい。 (;^ω^)

fizzbuzz7.cs
class FizzBuzz
{
  public static void Main()
  {
    string[] fb = { "FizzBuzz", "{0}",  "{0}",  "Fizz", "{0}",
                    "Buzz",     "Fizz", "{0}",  "{0}",  "Fizz",
                    "Buzz",     "{0}",  "Fizz", "{0}",  "{0}" };

    for (int i = 1; i <= 100; i++)
      System.Console.WriteLine(fb[i % 15], i);
  }
}

繰り返しを用いない縛り

縛りでなくただの厨二的ヤケクソですが。 (;^ω^) FizzBuzz問題が解けずに「printf文を100個書けばいいんだろ!」となったとき、 それでも正解だけど書き切れなければ恥を晒すだけです。
そこで賢くC言語のマクロを使って記述量を減らしてみました。 これなら2分以内に書けるかも? あとマクロを使ってますから手早く"Fizz"を"Bizz"に変更できるなど、 きちんと変更容易性も確保されていますよ(笑)

fizzbuzz.c
#include <stdio.h>

#define P(x)  printf("%d\n", x);
#define F     printf("Fizz\n");
#define B     printf("Buzz\n");
#define FB    printf("FizzBuzz\n");

int main(int argc, char *argv[])
{
  P( 1) P( 2) F P( 4) B F P( 7) P( 8) F B P(11) F P(13) P(14) FB
  P(16) P(17) F P(19) B F P(22) P(23) F B P(26) F P(28) P(29) FB
  P(31) P(32) F P(34) B F P(37) P(38) F B P(41) F P(43) P(44) FB
  P(46) P(47) F P(49) B F P(52) P(53) F B P(56) F P(58) P(59) FB
  P(61) P(62) F P(64) B F P(67) P(68) F B P(71) F P(73) P(74) FB
  P(76) P(77) F P(79) B F P(82) P(83) F B P(86) F P(88) P(89) FB
  P(91) P(92) F P(94) B F P(97) P(98) F B /* 100 */

  return 0;
}

0 件のコメント: