【エンジニア転職対策】FizzBuzz問題を解いてみよう


【エンジニア転職対策】FizzBuzz問題を解いてみよう

「エンジニアの採用面接でどんな問題が出題されるか知りたい」
「FizzBuzz問題を実際に解いてみたい」

このように感じているプログラミング初心者もいらっしゃるのではないでしょうか?そこで今回は企業で実際に出題されているレベルのFizzBuzz問題を紹介していきます。

ぜひ皆さんも実際に手を動かして、解けるか確認してみましょう。

目次
  1. FizzBuzz問題とは?
  2. Rubyの実行環境を用意しよう
  3. FizzBuzz問題 初級編
  4. 出力結果
  5. FizzBuzz問題 中級編
  6. カンマの条件分岐
  7. 出力結果
  8. 出力結果
  9. FizzBuzz問題 上級編
  10. まとめ

FizzBuzz問題とは?

『FizzBuzz』とは、企業が求める最低限のプログラミンング能力があるかを確認する問題です。 エンジニアの採用試験で多く出題されています。

例えば

次の出力結果になるコードを書いてください。使用するプログラミング言語に指定はありません。 1,2,3,4,5,6,7,8,9,10

このような問題が出され、大抵の場合は手書きでソースコードを書く必要があります。

Rubyの実行環境を用意しよう

次章からFizzBuzz問題を解いていきますが、その前にRubyを実行できる環境を用意しましょう。今回はRepl.itというサービスを使用して、コードを実行していきます。

①ブラウザでreplitを開く

②検索窓で「Ruby」を検索 image

③下の実行画面が現れるのを確認 image

④ソースコード部分に下記コードを貼り付け実行する print ”Hello Ruby”

image

replitは「ファイル一覧」「ソースコード」「実行結果」の3つに分かれています。 以降で紹介するコードは全てソースコード部分に書いていきます。

FizzBuzz問題 初級編

まずは初級レベルのFizzBuzz問題を解いてみましょう。

次の出力結果になるコードを書いてください。
使用するプログラミング言語に指定はありません。 1,2,3,4,5,6,7,8,9,10,11,12

【回答例①】

numbers = [1,2,3,4,5,6,7,8,9,10,11]
numbers.each do |number|
   if number == 11
    print number
  else
    print "#{number},"
  end
end

【回答例②】

(1..11).each do |number|
  if number == 11
    print number
  else
    print "#{number},"
  end
end

この問題ではRubyの『範囲(Range)オブジェクト』・『each』・『条件分岐』 に関する理解が必要です。ソースコードの中で特にポイントである部分を抜粋して解説していきます。

ポイント① 範囲オブジェクト
範囲オブジェクトについてみていきましょう。今回の問題では、まず1〜11の連続したデータを用意してあげる必要があります。

回答例①のように配列を使ってnumbersのように定義してもOKが、1〜100を出力する場合は大変ですよね。そこでRubyには『範囲オブジェクト』という便利なものが用意されています。

コードで使用している「(1..11)」が範囲オブジェクトです。これは「1,2,3,4,5,6,7,8,9,10,11」と同じ意味となります。範囲オブジェクトの書き方は下記のように決まっています。

(範囲開始値..範囲終了値)

このように範囲開始値と範囲終了値を書くだけで、Rubyが連続した数字の羅列だと認識してくれるのです。

ポイント② eachメソッド
次に『each』メソッドについてみていきましょう。eachメソッドは配列やハッシュなど値が格納されているものから、抜き出す処理です。

下記のコードは、1〜11の範囲オブジェクトの中から1から順番に11まで取り出すという意味になります。取り出した値はnumberという変数に代入されます。

ちなみにnumberの部分は好きな名前で問題ありませんが、変数名を見て直感的に何を表しているのか分かるようにしておくことをおすすめします。

(1..11).each do |number|

ポイント③ 条件分岐
最後に条件分岐についてみていきましょう。今回期待する出力結果は、下記のように数字と数字の間に「,(カンマ)」が必要になります。

例えば条件分岐を使わず次のようなコードにした場合、11の後にも「,」が入ってしまい、期待する出力結果と異なってしまいます。

(1..11).each do |number|
  print "#{number},"
end

#出力結果
1,2,3,4,5,6,7,8,9,10,111,2,3,4,5,6,7,8,9,10,11,

ここで1〜10と11で出力結果を変える必要があると分かります。そこで使用するのが『条件分岐』です。

 if number == 11
    print number
  else
    print "#{number},"
  end

numberが11の場合、「,」を付けずにそのままnumberの値を出力し、逆に11以外の場合はnumberの値の後ろに「,」が付きます。

ちなみに下記コードのように変数と文字列を一緒に出力したい場合、変数を#{}で囲む必要があるので注意しましょう。

“#{number},”

今回のFizzBuzzは、以上のようなポイントの知識が求められる問題でした。

FizzBuzz問題 中級編

次はもう少し難しいFizzBuzz問題を解いてみましょう。FizzBuzz問題の中でも特に有名なものです。

次の出力結果になるコードを書いてください。
3の倍数なら「Fizz」 5の倍数なら「Buzz」 両方の倍数なら「FizzBuzz」となるようにしてください。 1,2,Fizz,4,Buzz,Fizz,7,8,Fizz,Buzz,11,Fizz,13,14,FizzBuzz,16,17,Fizz,19,Buzz,Fizz,22,23,Fizz,Buzz,26,Fizz,28,29,FizzBuzz

初級編よりも条件分岐の数が増えて少し難しく感じた方もいるかもしれません。回答例のコードについて詳しく解説していきます。

【回答例】

(1..30).each do |number|
 #出力結果の条件分岐
 if number % 15 == 0
    print "FizzBuzz"
  elsif number % 3 == 0
    print "Fizz"
  elsif number % 5 == 0
    print "Buzz"
  else
    print "#{number}"
  end

#カンマの条件分岐
  if number == 30
    print ""
  else
    print ","
  end
end

ポイント① 〇〇の倍数の条件分岐

ある数字が〇〇の倍数の場合、〇〇で割った時の余りが0です。例えば9を3で割った場合の余りは0なので、9は3の倍数であると言えます。

出力結果を確認すると、下記のような条件になっていることが分かります。そのため4つの条件を作成する必要がありそうです。

・「3の倍数」の場合、「Fizz」を出力 ・「5の倍数」の場合、「Buzz」を出力 ・「15の倍数」の場合、「FizzBuzz」を出力 ・「それ以外」の場合、数字をそのまま出力

条件分岐をコードでそのまま表現すると、下記のようになります。

(1..30).each do |number|
  if number % 3 == 0
    print "Fizz"
  elsif number % 5 == 0
    print "Buzz"
  elsif number % 15 == 0
    print "FizzBuzz"
  else
    print "#{number}"
  end

  if number == 30
    print ""
  else
    print ","
  end
end

#出力結果
1,2,Fizz,4,Buzz,Fizz,7,8,Fizz,Buzz,11,Fizz,13,14,Fizz,16,17,Fizz,19,Buzz,Fizz,22,23,Fizz,Buzz,26,Fizz,28,29,Fizz

出力結果は一見すると問題なさそうですが、数字が30の場合「Fizz」と表示されています。本来は30は3の倍数かつ5の倍数なので「FizzBuzz」である必要があります。

条件分岐を作る際に分岐は上から処理されていくことに注意しなければいけません。先程の条件分岐部分のコードをもう一度見てみましょう。

 if number % 3 == 0 #3の倍数か判定
    print "Fizz"
  elsif number % 5 == 0 #5の倍数か判定
    print "Buzz"
  elsif number % 15 == 0 #15の倍数か判定
    print "FizzBuzz"
  else
    print "#{number}"
  end

この条件分岐は次のような流れになります。 ①3の倍数か判定→②5の倍数か判定→③15の倍数か判定→④それ以外を出力

数字が30の場合、まず①に合致されて②以降の処理はされません。そのため3の倍数の出力結果である「Fizz」となってしまったわけです。

この問題を解消するために下記のように条件分岐を修正する必要があります。

 if number % 15 == 0
    print "FizzBuzz"
  elsif number % 3 == 0
    print "Fizz"
  elsif number % 5 == 0
    print "Buzz"
  else
    print "#{number}"
  end

ポイント② 「,(カンマ)」を出力する条件

次に「,」の出力に関してみていきましょう。

これに関しては初級編と考え方は同じです。1〜29の場合は出力結果の後に「,」を付け、30の場合は「,」を付けないようにします。

ここでも下記のように条件分岐を作るだけでOKです。

 if number == 30
    print ""
  else
    print ","
  end

ちなみに下記のようにコードを書くとエラーが出てしまいます。

(1..30).each do |number|
  if number % 3 == 0
    print "Fizz"
  elsif number % 5 == 0
    print "Buzz"
  elsif number % 15 == 0
    print "FizzBuzz"
  else
    print "#{number}"
  end
end

if number == 30
  print ""
else
  print ","
end

#出力結果
undefined local variable or method `number' for main:Object (NameError)

出力結果のエラーは「number」という変数が定義されていないという意味になります。numberを定義しているのは、each文の箇所なのでその中でしか使うことができません。

そのためeach文の外でnumberを使用しているので、エラーとなるわけです。

FizzBuzz問題 上級編

最後にFizzBuzz問題の上級編にトライしてみましょう。

次の出力結果になるコードを書いてください。F[i] = F[i-1] + F[i-2]の関係になっています。 1 1 2 3 5 8 13 21 34 55

今回の問題は『フィボナッチ数列』と呼ばれる数字の羅列です。フィボナッチ数列とは2つ前の数字と1つ前の数字を足してできた数列を指します。

例えば問題の「2」は2つ前の「1」と1つ前の「1」の足し算の結果であり、同じく「13」は「5」と「8」の和となっています。

しかし1番目と2番目の「1」は上記のようなルールになっていません。ここで初級・中級編で出てきた条件分岐が必要になりそうですね。

【回答例】

num = []
num[1] = 1; 
num[2] = 1;
 print "1 1 "

(3..10).each do | i |
  num[i] = num[i-1] + num[i-2]
  print "#{num[i]} "
end

ポイント 範囲オブジェクト

今回も初級・中級編と同じく『範囲オブジェクト』を使ってコードを書いていきます。3番目以降の要素から2個前の数字と1個前の数字の和になるので、下記のようなコードとなります。

(3..10).each do | i |
  num[i] = num[i-1] + num[i-2]
  print "#{num[i]} "
end

このように使用する知識は高くないのですが、フィボナッチ数列という概念が出てきたので難しく感じたかもいるかもしれません。ぜひ回答例を見返して復習してみるのも良いかもしれません。

Webサイト担当者としてのスキルが身に付く

無料カウンセリングはこちら

まとめ

ここまで様々なレベルのFizzBuzz問題を解説してきました。FizzBuzz問題で問われるプログラミングのレベルは高くありませんが、慣れていないと難しく感じると思います。

いろいろなFizzBuzz問題を解いて、出題内容や形式に慣れておきましょう!


関連記事

ヤマモト
この記事を書いた人
ヤマモト
まずは7日間お試し!人気プログラミング講座を無料公開中
オンライン・プログラミングレッスンNo.1のCodeCamp