paiza プログラミング

[Ruby]paiza Bランクレベルアップメニュー 文字列の重複カウント (paizaランク C 相当)の解説

B-lvup_文字列の重複カウント

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

今回は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)

今回のまとめ

  • 文字列先頭から指定文字数分を参照する方法を扱いました。
  • 文字列中に指定文字列が何回出現するかをカウントしました。

文字列の問題が続きましたが、とりあえず今回でひと段落となります。お疲れ様でした!



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


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






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







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







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







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


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

© 2024 じゃいごテック