INDEX
■はじめに
Rubyの基礎的な問題をたくさん解くことで基本的な考え方やメソッドの使い方を定着させたい。
基本的にはAtCoderというプログラミングコンテスト(競技プログラミング)の過去問を使う。(AtCoderは難易度が分かれており、難易度の低いA問題かB問題を解いていく)
■問題
●出典
AtCoder Beginner Contest 017のB問題
https://atcoder.jp/contests/abc017/tasks/abc017_2
●問題文
高橋君は、ある日不思議な生物を見た。
その生物は choku 語という言語を用いていることがわかった。
文字列 S が以下の条件を満たしているときに S は choku 語であると定義する。
- 文字列 S が空文字列であるとき。
- 文字列 S が、choku 語である文字列 T の末尾に ch をつけた文字列であるとき。
- 文字列 S が、choku 語である文字列 T の末尾に o をつけた文字列であるとき。
- 文字列 S が、choku 語である文字列 T の末尾に k をつけた文字列であるとき。
- 文字列 S が、choku 語である文字列 T の末尾に u をつけた文字列であるとき。
choku 語の理解を深めるため、与えられた文字列が choku 語であるかを判定するプログラムを作成することにした。
●入力
入力は以下の形式で標準入力から与えられる。
X
- 1 行目には、choku 語か判定したい文字列 X(1≦∣X∣≦50) が与えられる。
- X は半角小文字アルファベットのみで構成されている。
●出力
X が choku 語なら文字列 YES
を、そうでないなら文字列 NO
を 1 行に出力せよ。出力の末尾にも改行を入れること。
■回答
●愚直に書く
難しかった…。
結論としては合わせて1時間くらい色々考えたけどできなかったのでギブアップしようとしたら、最後に閃いてどうにか回答できた。
正規表現を使うっぽいなぁと思いつつよくわかっていないのでまずは愚直な方法として
- 標準出力を取る
ch
だけ2文字で特殊なのでgsub
で数字の1
に置き換えておく- 標準入力で取った数字が
["1", "o", "k", "u"]
だけで構成された文字列ならYES、違ったらNOと返す
というようなことをしようと思っていて、最後の工程を実現するためにinclude?
やany?
やall?
を調べていたけど全然できなかった。一度諦めた後に、もっとシンプルに演算子の差集合でできてしまうのではと閃いた。
x = gets.chomp
s = x.gsub(/ch/, '1').split('').map(&:to_s)
choku = ["1", "o", "k", "u"]
puts s - choku == [] ? "YES" : "NO"
通った!!!
●リファクタリング/別アプローチ
今日はもう力尽きたので他の回答を見ます…!
●他の方の回答例
上位の方々は正規表現でバシッと出している。
●出てきたメソッド等
公式リファレンスを見る訓練。
-
String#gsub
https://docs.ruby-lang.org/ja/latest/method/String/i/gsub.html -
String#match
https://docs.ruby-lang.org/ja/latest/method/String/i/match.html -
Regexp#match
https://docs.ruby-lang.org/ja/latest/method/Regexp/i/match.html
■振り返りなど
結構時間がかかってキツかった…。さらに正規表現での回答をちゃんと咀嚼する時間が取れてないので、明日は次の問題に行くのではなく今回の別回答をしっかりやってみようかな…。
■5/2追記
正規表現を使った回答を確認。
下記の回答は自分にとってもわかりやすかった。
puts gets.chomp.gsub(/ch|o|k|u/, '') == '' ? 'YES' : 'NO'
もう少し平易な書き方にすると、
x = gets.chomp
if x.gsub(/ch|o|k|u/, '') == ''
puts 'YES'
else
puts 'NO'
end
標準入力をxで取って、正規表現を使ってch
o
k
u
があったら''
に置き換え(つまり文字を削除)して、その結果何も文字が残らなければ元の文字列はch
o
k
u
だけで構成されていたことになるのでYES
、何か文字が残ればNO
。なるほど〜!