paiza プログラミング

[Ruby]paiza Bランクレベルアップメニュー 文字と整数の組のソート (paizaランク C 相当)の解説

B-lvup_文字と整数の組のソート

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

今回はpaiza Bランクレベルアップメニュー から文字と整数の組のソートという問題を解説します。

この問題集はデータのソートに関する3個のSTEP問題(D級)FINAL問題(C級)で構成されていて、STEP問題を解いて行けばFINAL問題も解けるはず!となっています。

STEP問題を解いてみる

STEP問題は基本的なメソッドについての問題です。
簡単な解説は付けていますが、難しいと感じたら下記の記事も参考にしてみて下さい。

※過去に出題された小問題が出てくることがありますが、チケットに余裕があれば復習のつもりで取り組んでみましょう。

STEP1: インクリメント (paizaランク D 相当)

STEP1 は受け取った整数をインクリメント(+1)して出力する問題です。

解答例

<< EOS

入力例1
-10
出力例1
-9
入力例2
0
出力例2
1
入力例3
1
出力例3
2

EOS

n = gets.to_i
puts n + 1

解答例: 標準入力で受けとった文字列を整数型に変換、+1 して出力しています。


STEP2: 数字のみの出力 (paizaランク D 相当)

STEP2 は複数の半角スペース区切りの文字と整数のペアが渡され、整数だけを先頭から順に出力する問題です。

解答例

<<"EOS"

4
S 1
F 2
E 5
Y 6

出力例1
1
2
5
6

入力例2
3
S -3
G -5
R -35

出力例2
-3
-5
-35

入力例3
6
A 12
E 42
G -8
R -7
Y 56
E 22

出力例3
12
42
-8
-7
56
22

EOS

# [解答例1]
n = gets.to_i
ary = []
n.times do
  s, d = gets.split
  ary.push([s, d.to_i])
end
ary.each do |s, d|
  puts d
end

# [解答例2]
n = gets.to_i
hash = {}
n.times do
  s, d = gets.split
  hash[s] = d.to_i
end
puts hash.values

解答例1: 文字と数字のペアを配列で受け取って、二次元配列の先頭から順に2番目の要素を出力しています。

解答例2: 文字と数字のペアを配列で受け取り、文字をキー、数字を値にしたハッシュに格納して、valuesメソッドで値の配列を取得して出力しています。


STEP3: 昇順ソート出力 (paizaランク D 相当)

STEP2 は半角スペース区切りの整数を受け取り、昇順に並べ替えて出力する問題です。

解答例

<<"EOS"

入力例1
8
90 777 8888 121 333 4 29 2

出力例1
2
4
29
90
121
333
777
8888

入力例2
10
10 9 8 7 6 5 4 3 2 1

出力例2
1
2
3
4
5
6
7
8
9
10

入力例3
1
3

出力例3
3

EOS

# [解答例1]
n = gets.to_i
ary = gets.split.map(&:to_i)

sorted_ary = []
ary.each do |t_n|
  inserted = false
  sorted_ary.each_with_index do |a_n, idx|
    if t_n < a_n
      sorted_ary.insert(idx, t_n)
      inserted = true
      break
    end
  end
  sorted_ary << t_n if not inserted
end
puts sorted_ary

# [解答例2]
n = gets.to_i
ary = gets.split.map(&:to_i)

puts ary.sort

解答例1: 配列aryの先頭から順に値を取り出し、sorted_aryの値と比較して昇順になるようにsorted_aryに挿入しています。
※ 解説のために自前でソートを実装しましたが、通常はsortメソッドを使った方が楽なうえに処理も早いです。

解答例2: sortメソッドで昇順の配列を生成して出力しています。


文字と整数の組のソート (paizaランク C 相当)を解いてみる

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

問題

1行目に行数を表す整数 n、続く n 行の各行で「文字」と「整数」の組が空白区切りで入力されます。
n 個の組を、「整数」の値で昇順に並べ変え、「文字」を出力してください。

入力される値

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

n
S_1 D_1
S_2 D_2
...
S_i D_i
...
S_n D_n

S_i は「文字」で、D_i は「整数」です。
入力される文字 S_i は、同じ文字が複数入力されることはなく、整数 D_i も同様です。
入力値最終行の末尾に改行が1つ入ります。

期待する出力

n 個の組を、「整数」の値で昇順に並べ変え、「文字列」を1行ずつ出力してください。

条件

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

  • 1 ≦ n ≦ 100
  • -10,000 ≦ D_i ≦ 10,000
  • S_iは半角英文字1文字
  • iとjが異なるなら、D_iとD_jは異なる
  • iとjが異なるなら、S_iとS_jは異なる
入力例1
2
A 1
B 2
出力例1
A
B
入力例2
3
G 0
S 3
E -2
出力例2
E
G
S
入力例3
5
H -2
R 0
W -5
A -1
E -20
出力例3
E
W
H
A
R
攻略ポイント

ポイント

  • sort_byメソッドで二次元配列(又はハッシュ)の指定要素で昇順ソートを行う
  • 二次元配列(又はハッシュ)の指定された要素だけを出力する

デバッグを楽にするためにメソッドを作成します。メソッドについては下記の記事も参考にしてみて下さい。

問題を解く流れ

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

INPUT1 = <<~"EOS"
  2
  A 1
  B 2
EOS
OUTPUT1 = <<~"EOS"
  A
  B
EOS

INPUT2 = <<~"EOS"
  3
  G 0
  S 3
  E -2
EOS
OUTPUT2 = <<~"EOS"
  E
  G
  S
EOS

INPUT3 = <<~"EOS"
  5
  H -2
  R 0
  W -5
  A -1
  E -20
EOS
OUTPUT3 = <<~"EOS"
  E
  W
  H
  A
  R
EOS

# 確認用コード
p INPUT1
# > "2\nA 1\nB 2\n"
p OUTPUT1
# > "A\nB\n"
p INPUT2
# > "3\nG 0\nS 3\nE -2\n"
p OUTPUT2
# > "E\nG\nS\n"
p INPUT3
# > "5\nH -2\nR 0\nW -5\nA -1\nE -20\n"
p OUTPUT3
# > "E\nW\nH\nA\nR\n"

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

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

def solve(input_lines)
  # 入力データ受け取り
  input_lines = input_lines.split("\n")
  n = input_lines.shift.to_i

  # 確認用コード
  [n, input_lines]
end

# 確認用コード
p solve(INPUT1)
# > [2, ["A 1", "B 2"]]
p solve(INPUT2)
# > [3, ["G 0", "S 3", "E -2"]]
p solve(INPUT3)
# > [5, ["H -2", "R 0", "W -5", "A -1", "E -20"]]

データが正しく受け取れていれば、solve メソッドに文字と数字のペアを数字の昇順でソートする処理を追加していきます。

  • 文字と整数のペアを配列に格納する(二次元配列になる)
  • 2番目の要素(整数)で昇順に並び替えた配列を生成する
def solve(input_lines)
  # 入力データ受け取り
  input_lines = input_lines.split("\n")
  n = input_lines.shift.to_i

  # 文字と整数のペアを配列に格納する
  ary = input_lines.map do |line|
    s, d = line.split
    [s, d.to_i]
  end

  # 2番目の要素(整数)で昇順に並び替えた配列を生成する
  sorted_ary = ary.sort_by { |x| x[1] }

  # 確認用コード
  sorted_ary.map { |x| x[0] }
end

# 確認用コード
p solve(INPUT1)
# > ["A", "B"]
p solve(INPUT1) == OUTPUT1
# > false
p solve(INPUT2)
# > ["E", "G", "S"]
p solve(INPUT2) == OUTPUT2
# > false
p solve(INPUT3)
# > ["E", "W", "H", "A", "R"]
p solve(INPUT3) == OUTPUT3
# > false

あとは出力形式を整えれば完成です。

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

def solve(input_lines)
  # 入力データ受け取り
  input_lines = input_lines.split("\n")
  n = input_lines.shift.to_i

  # 文字と整数のペアを配列に格納する
  ary = input_lines.map do |line|
    s, d = line.split
    [s, d.to_i]
  end

  # 2番目の要素(整数)で昇順に並び替えた配列を生成する
  sorted_ary = ary.sort_by { |x| x[1] }

  # 文字列に変換して末尾に改行を追加する
  sorted_ary.map { |x| x[0] }.join("\n") << "\n"
end

# 確認用コード
p solve(INPUT1)
# > "A\nB\n"
p solve(INPUT1) == OUTPUT1
# > true
p solve(INPUT2)
# > "E\nG\nS\n"
p solve(INPUT2) == OUTPUT2
# > true
p solve(INPUT3)
# > "E\nW\nH\nA\nR\n"
p solve(INPUT3) == OUTPUT3
# > true

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

解答コード
def solve(input_lines)
  # 入力データ受け取り
  input_lines = input_lines.split("\n")
  n = input_lines.shift.to_i

  # 文字と整数のペアを配列に格納する
  ary = input_lines.map do |line|
    s, d = line.split
    [s, d.to_i]
  end

  # 2番目の要素(整数)で昇順に並び替えた配列を生成する
  sorted_ary = ary.sort_by { |x| x[1] }

  # 文字列に変換して末尾に改行を追加する
  sorted_ary.map { |x| x[0] }.join("\n") << "\n"
end

puts solve(STDIN.read)
他の解答例
  • 数値で昇順ソートした配列をハッシュに変換し、keysメソッドで文字の配列を取り出す。
def solve(input_lines)
  # 入力データ受け取り
  n, *lines = input_lines.split("\n")

  # 文字と整数のペアを配列に格納する
  ary = lines.map do |line|
    s, d = line.split
    [s, d.to_i]
  end

  # 整数で昇順ソートしてハッシュに変換する
  sorted_hash = ary.sort_by { |x| x[1] }.to_h

  # ハッシュのキーの配列を改行区切りで出力する
  sorted_hash.keys.join("\n") << "\n"
end

puts solve(STDIN.read)

今回のまとめ

  • sort_byメソッドを使って二次元配列(又はハッシュ)の指定された要素で昇順ソートを行いました
  • 二次元配列はmapメソッド、ハッシュはkeysメソッドで指定された要素だけの配列を取り出しました
    (ハッシュの値の配列はvaluesメソッドで取り出すことが出来る)

データの種類や処理内容によって二次元配列とハッシュを使い分けられると便利ですね!



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


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






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







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







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







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


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

© 2024 じゃいごテック