paiza プログラミング

[Ruby]paiza Cランクレベルアップメニュー 標準入出力 (paizaランク C 相当)の解説

paizaCランクレベルアップ_標準入出力

こんにちは!じゃいごテックのあつしです。

今回はpaiza Cランクレベルアップメニュー から標準入出力という問題を解説していきたいと思います。

この問題集は標準入出力に関する6個のSTEP問題(D級)FINAL問題(C級)で構成されていて、STEP問題を解いて行けばFINAL問題も解けるはず!となっています。

STEP問題を解いてみる

STEP問題は標準入力の基本問題です。
簡単な解説は付けていますが、難しいと感じたら下記の記事も参考にしてみて下さい。

STEP1: 単純な入出力 (paizaランク D 相当)

STEP1 は標準入力からの文字列をそのまま出力する問題です。

解答例

<<EOS

入力例1
paiza

出力例1
paiza

入力例2
Paiza21
出力例2
paiza21

EOS

# [解答例1]
puts gets

# [解答例2] chomp を付けてもok
puts gets.chomp

getsメソッド で標準入力から文字列を受け取り、putsメソッド でそのまま標準出力に渡します。
putsメソッド は末尾に改行が無い場合、自動で改行を追加して出力、末尾に改行がある場合はそのまま出力しますので、 chompメソッド は有っても無くても構いません。


STEP2: 複数行にわたる出力 (paizaランク D 相当)

STEP2 は標準入力で整数 n が与えられ、 n 回、指定文字列 "paiza" を改行区切りで出力する問題です。

解答例

<<EOS

入力例1
n

出力例1
paiza
paiza

入力例2
5

出力例2
paiza
paiza
paiza
paiza
paiza

EOS
 
# [解答例1]
puts "paiza\n" * gets.to_i

# [解答例2]
gets.to_i.times { puts "paiza" }

この問題のポイントは標準入力の文字列を to_iメソッド で整数にして処理を行うことと、改行区切りで複数行の出力を行うことです。解答例1では文字列の連結を使い、解答例2では繰り返し処理を使っています。


STEP3: 複数行にわたる入力 (paizaランク D 相当)

STEP3 は標準入力から1行目でデータ件数 nを受け取り、続くn行のデータを受け取り、そのまま出力する問題です。

解答例

<<EOS
 
入力例1
2
1
2

出力例1
1
2

入力例2
3
10
5
39

出力例2
10
5
39

EOS

# [解答例1]
n = gets.to_i
n.times { puts gets }

# [解答例2]
get.to_i.times { puts gets }

この問題のポイントは、標準入力の文字列を to_iメソッド で整数にして処理を行うことと、繰り返し処理で入力・出力を行うことです。


STEP4: 入力の配列による保持 (paizaランク D 相当)

STEP4 は標準入力から1行目でデータ件数 nを受け取り、続くn行のデータを受け取って整数に変換し、受け取った値の中で最大の値を表示する問題です。

解答例

<<EOS

入力例1
2
4
7

出力例1
7

入力例2
3
20
19
2

出力例2
20

EOS

# [解答例1]
ary = []
max_num = 0
gets.to_i.times do
  num = gets.to_i
  max_num = num if max_num < num
  ary.push(num)
end
puts max_num

# [解答例2]
ary = gets.to_i.times.map { gets.to_i }
puts ary.max

解答例1は現時点での最大値 max_num受け取った値 numを比較・上書きしながら最大値を探しつつ、配列 ary にデータを追加しています。受け取る値は 1から50の間の整数であることがわかっているので、max_num を 0 で初期化することによって1回目の比較で必ず上書きされます。

解答例2は一旦全てのデータを配列に格納した後、maxメソッドで最大値を検索して出力しています。


STEP5: 半角スペース区切りでの出力 (paizaランク D 相当)

STEP5 は標準入力で整数 n が与えられ、 n 個の指定文字列 "paiza" をスペース区切りで出力する問題です。

解答例

<<EOS

入力例1
2

出力例1
paiza paiza

入力例2
3

出力例2
paiza paiza paiza

EOS

# [解答例1]
result = ""
(1..gets.to_i).each do |count|
  result << "paiza"
  break if count == n
  result << " "
end
puts result

# [解答例2]
puts Array.new(gets.to_i, "paiza").join(" ")

解答例1: n回の繰り返し処理を行い、空文字で初期化した result に "paiza" を連結します。n-1回目までは半角スペースを連結していますが、n回目(最後)は break で繰り返し処理を抜けるので、半角スペースを連結しません。

解答例2: サイズが  n で、初期値が "paiza" の配列を生成し、joinメソッドで半角スペース区切りの文字列を生成して表示しています。


STEP6: 改行区切りでの出力 (paizaランク D 相当)

STEP6 は1行目に要素数 n、2行目にn個の整数が半角スペースで与えられ、n個の整数を改行区切りで出力する問題です。

<<EOS

入力例1
2
1 5

出力例1
1
5

入力例2
3
4 30 12

出力例2
4
30
12

EOS

# [解答例1]
gets
gets.split.each do |value|
  puts value
end

# [解答例2]
gets
puts gets.split

解答例1: 1行目の入力を捨てて、2行目の入力を半角スペースで分割した配列の各要素を出力しています。

解答例2: 1行目の入力を捨てて、2行目の入力を半角スペースで分割した配列に対してputsメソッドで出力しています。
配列に対してputsメソッドを使うと、各要素を改行区切りで出力してくれます。

標準入出力 (paizaランク C 相当) を解いてみる

※ paiza Cランクレベルアップメニューより

問題

毎年 5 月 1 日に、自分が運営している会社の社員一覧表を作成しています。表は年度ごとに更新され、社員の名前と年齢が載っています。
ところで、会社のメンバーは昨年度から全く変わらず、社員の誕生日は全員 7 月 7 日だったので、前年度の一覧表の年齢欄をそれぞれ +1 するだけで今年度の表が作れることにパイザ君は気づきました。

昨年度の一覧表が与えられるので、今年度の一覧表を出力してください。

入力される値

入力は以下のフォーマットで与えられます。

N
s_1 a_1
...
s_N a_N

1 行目には社員の数を表す整数 N が与えられ、2 行目 〜 (N + 1) 行目の各行では、社員の名前を表す文字列 s_i とその社員の昨年度の年齢を表す整数 a_i が半角スペース区切りで与えられます(1 ≤ i ≤ N)。

入力値最終行の末尾に改行が1つ入ります。

期待する出力

入力された通りの順番で、社員 s_i の名前と、その社員の今年度の年齢を半角スペース区切りでN行出力してください。

s_1 (a_1 + 1)
...
s_N (a_N + 1)

末尾に改行を入れ、余計な文字、空行を含んではいけません。

条件

すべてのテストケースにおいて、以下の条件をみたします。

  • 1 ≤ N ≤ 50
  • s_i(1 ≤ i ≤ N)は 1 文字以上 10 文字以下の文字列
  • s_i(1 ≤ i ≤ N)の各文字は英小文字または英大文字または数字
  • 18 ≤ a_i ≤ 120(1 ≤ i ≤ N)
入力例1
1
Yamada 30
出力例1
Yamada 31
入力例2
3
Tanaka 18
Sato 50
Suzuki 120
出力例2
Tanaka 19
Sato 51
Suzuki 121
攻略ポイント

ポイント

  • 標準入力からの複数行データ取得
  • 文字列の分割、連結
  • 文字列型 ⇔ 整数型 の型変換

デバッグを楽にするためにメソッドを作成します。小問題解説で紹介した記事プラス下記の記事も参考にしてみて下さい。

問題を解く流れ

入出力例をコピペしてヒアドキュメントで変数に代入し、データを確認します。正しく受け取れていれば確認用コードは削除します。

INPUT1 = <<~"EOS"
  1
  Yamada 30
EOS
OUTPUT1 = <<~"EOS"
  Yamada 31
EOS

INPUT2 = <<~"EOS"
  3
  Tanaka 18
  Sato 50
  Suzuki 120
EOS
OUTPUT2 = <<~"EOS"
  Tanaka 19
  Sato 51
  Suzuki 121
EOS

# 確認用コード
p INPUT1
# > "1\nYamada 30\n"
p INPUT2
# > "3\nTanaka 18\nSato 50\nSuzuki 120\n"

続いて問題を解くメソッド( solve メソッドとします)を変数の下に定義します。

まず、入力データを受け取る処理を書きます。

入力された文字列を改行で分割し、1行目は使わないので _ に代入、2行目以降を配列 members に代入します。

def solve(input_lines)
  # input_lines を改行区切りで分割する
  # 1行目を _ に代入(使わないので捨てる)
  # 2行目以降を members 配列に格納
  _, *members = input_lines.split("\n")

  # 確認用コード
  members
end

# 確認用コード
p solve(INPUT1)
# > ["Yamada 30"]
p solve(INPUT2)
# > ["Tanaka 18", "Sato 50", "Suzuki 120"]

名前と年齢が半角で連結された文字列データが正しく受け取れていれば、次に solve メソッドに年齢を +1 する処理を追加していきます。

  • members の先頭から次々と要素を取り出して、半角スペースで分割して名前 name年齢 ageに分けます。
  • 年齢 age を整数型に変換して +1 します。
  • 名前 name年齢 age を半角スペース区切りの文字列に変換します。
  • map!メソッドを使ってそれぞれの要素を処理した結果で members を上書きします。
def solve(input_lines)
  # input_lines を改行区切りで分割する
  # 1行目を _ に代入(使わないので捨てる)
  # 2行目以降を members 配列に格納
  _, *members = input_lines.split("\n")

  members.map! do |member|
    name, age = member.split
    "#{name} #{age.to_i + 1}"
  end

  # 確認用コード
  members
end

# 確認用コード
p solve(INPUT1)
# > ["Yamada 31"]
p solve(INPUT1) == OUTPUT1
# > false
p solve(INPUT2)
# > ["Tanaka 19", "Sato 51", "Suzuki 121"]
p solve(INPUT2) == OUTPUT2
# > false

各社員の年齢が +1 されていれば、あとは出力を整えれば完成です。

p solve(INPUT1)puts solve(STDIN.read) に変更すれば正解となりますが、p solve(INPUT1) == OUTPUT1 -> true を確認するために、結果を改行区切りの文字列に変換して、末尾にも改行を加えます。

def solve(input_lines)
  # input_lines を改行区切りで分割する
  # 1行目を _ に代入(使わないので捨てる)
  # 2行目以降を members 配列に格納
  _, *members = input_lines.split("\n")

  members.map! do |member|
    name, age = member.split
    "#{name} #{age.to_i + 1}"
  end

  # members を改行区切りにして末尾にも改行を加えた文字列に変換する
  members.join("\n") << "\n"
end

# 確認用コード
p solve(INPUT1)
# > "Yamada 31\n"
p solve(INPUT1) == OUTPUT1
# > true
p solve(INPUT2)
# > "Tanaka 19\nSato 51\nSuzuki 121\n"
p solve(INPUT2) == OUTPUT2
# > true

確認用コードを標準入力からのデータ受け取りに変更して、動作確認をしたら提出します。
複数行のデータ受け取りなので STDIN.read を使います。(入力終了は Ctrl+D 又は Ctrl+Z)

解答コード
def solve(input_lines)
  # input_lines を改行区切りで分割する
  # 1行目を _ に代入(使わないので捨てる)
  # 2行目以降を members 配列に格納
  _, *members = input_lines.split("\n")

  members.map! do |member|
    name, age = member.split
    "#{name} #{age.to_i + 1}"
  end

  # members を改行区切りにして末尾にも改行を加えた文字列に変換する
  members.join("\n") << "\n"
end

puts solve(STDIN.read)

今回のまとめ

この問題集を通して以下の操作を覚えることが出来ました。

  • 複数行のデータ受け取り
  • 繰り返し処理
  • 文字列の分割、結合、繰り返し
  • 文字列型⇔整数型の変換

標準入出力は競プロに挑戦するための基本になります。

色々なパターンの入出力に挑戦して、引き出しを増やしていきましょう!



【PR】アルゴリズム学習でお世話になった本


アルゴリズム関連の技術書は大抵C/C++で書かれていますが、ある程度プログラムが出来れば、処理の流れは理解することが出来ます。






通称: 螺旋本。C++で解説されています。AOJ(Aizu Online Judge)を運営している会津大学の渡辺准教授が書いた本です。データ構造や計算量の内容から丁寧に書いてありますのでアルゴリズム学習の最初の参考書としてオススメです。







通称: 蟻本。C++で解説されています。競技プログラミング中級者の定番書と言われていて、競技プログラミングで利用できる色々なアルゴリズムを学ぶことが出来ます。かなり高度な内容も含まれているので1冊分を完全に理解するのにはかなりの時間がかかりそうですが、手元に置いて何度も読み返しています。







通称: チーター本。C#, C++, JAVAでTopcoderの問題を解説しています。初心者~中級者向けに書かれているので解説が非常に丁寧です。







Python3でアルゴリズムを解説している本です。講義スタイルの本で、図やフローチャートを使ってアルゴリズムとデータ構造についてしっかりと説明されています。代わりにコードは少なめです。Pythonコードが読めなくても十分理解できると思います。


-paiza, プログラミング
-, , , , ,

© 2024 じゃいごテック