こんにちは!じゃいごテックのあつしです。
今回はpaiza Bランクレベルアップメニュー から文字の重複カウントという問題を解説します。
この問題集は文字列に関する5個のSTEP問題(D級)とFINAL問題(C級)で構成されていて、STEP問題を解いて行けばFINAL問題も解けるはず!という構成となっています。
STEP問題を解いてみる
STEP問題は文字列の基本問題です。
簡単な解説は付けていますが、難しいと感じたら下記の記事も参考にしてみて下さい。
※過去に出題された小問題が出てくることがありますが、チケットに余裕があれば復習のつもりで取り組んでみましょう。
STEP1: 文字列の長さ (paizaランク D 相当)
STEP1 は文字列の長さを出力する問題です。
解答例
<<"EOS" 入力例1 input 出力例1 5 入力例2 abc123 出力例2 6 入力例3 0123456789 出力例3 10 EOS s = gets.chomp puts s.length
解答例: lengthメソッド
で文字列の長さを取得して出力しています。
STEP2: 文字列の1文字目 (paizaランク D 相当)
STEP2 は文字列の1文字目を出力する問題です。
解答例
<<"EOS" 入力例1 read 出力例1 r 入力例2 scale 出力例2 s 入力例3 representative 出力例3 r EOS s = gets.chomp puts s[0]
解答例: 文字列[0]
で文字列の1文字目を参照して出力しています。
STEP3: 1文字ずつ出力 (paizaランク D 相当)
STEP3 は与えられた文字列を先頭から1文字ずつ出力する問題です。
解答例
<<"EOS" 入力例1 read 出力例1 r e a d 入力例2 scale 出力例2 s c a l e 入力例3 representative 出力例3 r e p r e s e n t a t i v e EOS # [解答例1] s = gets.chomp 0.upto(s.length - 1) { |idx| puts idx } # [解答例2] s = gets.chomp puts s.chars # [解答例3] s = gets.chomp puts s.split("")
解答例1: lengthメソッド
で配列の長さを求め、0から配列の長さ-1 でインデックスをインクリメントして、配列の要素を先頭から順に出力しています。
解答例2: charsメソッド
で文字列を1文字区切りの配列に変換して、putsメソッドで配列の先頭から順に出力しています。
解答例3:splitメソッド
で文字列を1文字区切りの配列に変換して、putsメソッドで配列の先頭から順に出力しています。
STEP4: 文字列の1、2文字目 (paizaランク D 相当)
STEP4 は与えられた文字列の1文字目と2文字目を半角スペースで連結して出力する問題です。
解答例
<<"EOS" 入力例1 read 出力例1 r e 入力例2 scale 出力例2 s c 入力例3 representative 出力例3 r e EOS # [解答例1] s = gets.chomp puts "#{s[0]} #{s[1]}" # [解答例2] s = gets.chomp puts s.chars[0..1].join(" ")
解答例1: 文字列の1文字目と2文字目を参照して式展開で出力しています。
解答例2: 文字列の1文字目と2文字目を配列にしてjoinメソッド
で半角スペースで連結して出力しています。
STEP5: 文字列の n 文字目と n + 1 文字目 (paizaランク D 相当)
STEP5 は与えられた文字列の指定位置と指定位置の次の文字を半角スペースで連結して出力する問題です。
解答例
<<"EOS" 入力例1 2 read 出力例1 e a EOS n = gets.to_i s = gets.chomp puts "#{s[n - 1]} #{s[n]}" n = gets.to_i s = gets.chomp puts s.chars[n - 1..n].join(" ")
解答例1: 文字列のn文字目とn+1文字目を参照して式展開で出力しています。
解答例2: 文字列のn文字目とn+1文字目を配列にしてjoinメソッド
で半角スペースで連結して出力しています。
文字列の重複カウント (paizaランク C 相当)を解いてみる
※ paiza Bランクレベルアップメニューより
問題
1行目で文字列 s、2行目で文字列 t が入力されます。
s が t の中で何回出現するかカウントして出力してください。
入力される値
入力は以下のフォーマットで与えられます。
s
t
入力値最終行の末尾に改行が1つ入ります。
期待する出力
出現回数を1行で出力してください。
最後は改行し、余計な文字、空行を含んではいけません。
条件
すべてのテストケースにおいて、以下の条件をみたします。
- 1 ≦ (文字列 s の長さ) ≦ 10,000
- 1 ≦ (文字列 t の長さ) ≦ 10,000
- 文字列 s, t は、半角アルファベットで構成された文字列
- 入力例1
- AA
abdeeAAbAAAbfde
- 出力例1
- 3
- 入力例2
- el
scale
- 出力例2
- 0
- 入力例3
- Ji
JiJiiJiIjiIJjIJi
- 出力例3
- 4
攻略ポイント
ポイント
文字列s
の先頭から順にt文字分
を参照して文字列t
と一致するかを調べる。
(文字列sの文字数を超えないように繰り返し処理を設定する)
デバッグを楽にするためにメソッドを作成します。メソッドについては下記の記事も参考にしてみて下さい。
問題を解く流れ
入出力例をコピペしてヒアドキュメントで変数に代入し、データを確認します。正しく受け取れていれば確認用コードは削除します。
INPUT1 = <<~"EOS" AA abdeeAAbAAAbfde EOS OUTPUT1 = <<~"EOS" 3 EOS INPUT2 = <<~"EOS" el scale EOS OUTPUT2 = <<~"EOS" 0 EOS INPUT3 = <<~"EOS" Ji JiJiiJiIjiIJjIJi EOS OUTPUT3 = <<~"EOS" 4 EOS # 確認用コード p INPUT1 # > "AA\nabdeeAAbAAAbfde\n" p OUTPUT1 # > "3\n" p INPUT2 # > "el\nscale\n" p OUTPUT2 # "0\n" p INPUT3 # > "Ji\nJiJiiJiIjiIJjIJi\n" p OUTPUT3 # > "4\n"
続いて問題を解くメソッド( solve
メソッドとします)を変数の下に定義します。
まず、入力データを受け取る処理を書きます。
def solve(input_lines) s, t = input_lines.split # 確認用コード [s, t] end # 確認用コード p solve(INPUT1) # > ["AA", "abdeeAAbAAAbfde"] p solve(INPUT2) # > ["el", "scale"] p solve(INPUT3) # > ["Ji", "JiJiiJiIjiIJjIJi"]
データが正しく受け取れていれば、solve
メソッドに文字列sに文字列tが含まれているかを調べる処理を追加していきます。
- 0から
文字列sの文字数
-文字列tの文字数
までインデックスidx
をカウントする繰り返し処理を設定する
(文字列sの文字数を超えないように繰り返し処理を設定する) 文字列s
のインデックスidx
から文字列t文字分
までを参照して、文字列t
と一致するかを調べる
def solve(input_lines) s, t = input_lines.split s_len = s.length t_len = t.length result = 0 (0..t_len - s_len).each do |idx| result += 1 if t[idx..idx + s_len - 1] == s end # 確認用コード result end # 確認用コード p solve(INPUT1) # > 3 p solve(INPUT1) == OUTPUT1 # > false p solve(INPUT2) # > 0 p solve(INPUT2) == OUTPUT2 # > false p solve(INPUT3) # > 4 p solve(INPUT3) == OUTPUT3 # > false
あとは出力形式を整えれば完成です。
p solve(INPUT1)
を puts solve(STDIN.read)
(p solve(STDIN.read)
でも可)に変更すれば正解となりますが、p solve(INPUT1) == OUTPUT1 -> true
を確認するために、結果を改行区切りの文字列に変換して、末尾にも改行を加えます。
def solve(input_lines) s, t = input_lines.split s_len = s.length t_len = t.length result = 0 (0..t_len - s_len).each do |idx| result += 1 if t[idx..idx + s_len - 1] == s end # 文字列に変換して末尾に改行を追加する result.to_s << "\n" end # 確認用コード p solve(INPUT1) # > "3\n" p solve(INPUT1) == OUTPUT1 # > true p solve(INPUT2) # > "0\n" p solve(INPUT2) == OUTPUT2 # > true p solve(INPUT3) # > "4\n" p solve(INPUT3) == OUTPUT3 # > true
確認用コードを標準入力からのデータ受け取りに変更して、動作確認をしたら提出します。
複数行のデータ受け取りなので STDIN.read
を使います。(入力終了は Ctrl+D
又は Ctrl+Z
)
解答コード
def solve(input_lines) s, t = input_lines.split s_len = s.length t_len = t.length result = 0 (0..t_len - s_len).each do |idx| result += 1 if t[idx..idx + s_len - 1] == s end # 文字列に変換して末尾に改行を追加する result.to_s << "\n" end put solve(STDIN.read)
他の解答例
scanメソッド
で文字列s
に含まれる文字列t
を数える。
def solve(input_lines) s, t = input_lines.split t.scan(s).length end puts solve(STDIN.read)
今回のまとめ
- 文字列先頭から指定文字数分を参照する方法を扱いました。
- 文字列中に指定文字列が何回出現するかをカウントしました。
文字列の問題が続きましたが、とりあえず今回でひと段落となります。お疲れ様でした!