はじめに
Ruby学習の一環として「競技プログラミング(競プロ)」に挑戦します。
そのための学習の中で学んだことをアウトプットしていきます。
今回は「AtCoder Beginners Selection」の六問目(Some Sums)より。
https://atcoder.jp/contests/abs
問題
1以上N以下の整数のうち、
10進法でA以上B以下であるものの総和を求めなさい。
制約
1 ≤ N ≤ 10,000
1 ≤ A ≤ B ≤ 36
入力は全て整数である
入力は以下の形で与えられる。
N A B
# 例
20 2 5
出力例
# 上記例の場合
=> 84
20以下の整数のうち、各桁の和が2以上5以下なのは
2,3,4,5,11,12,13,14,20です。これらの合計である84を出力します。
解答①
まずは僕の解答から。
n, a, b = gets.split(" ").map(&:to_i)
r = 0
(1..n).each do |i|
r += i if i.to_s.split("").map(&:to_i).inject(:+).between?(a, b)
end
print r
この解答をする中で学んだメソッドを以下にまとめていきます。
splitメソッド
入力を受け取る時によく使ってましたが、
今回のeach文の中での使用で、改めてStringクラスのメソッドだと認識出来ました。
解答では一度String型に変換した上でsplitメソッドを使い、またInteger型に戻すということをしています。
#例
print "1234".split("")
=> ["1", "2", "3", "4"]
between?メソッド
self.between?(min, max)
#selfがminからmaxの間(min,max含む)であった場合、trueを返す
#例
print 6.between?(1, 5)
=> false
最小値と最大値を指定し、selfがその範囲内だった場合はtrueを返すこのメソッドを使って、
各桁の和がa以上b以下の範囲内かを判定しています。
解答②
他の方の解答を見てみます。
n, a, b = gets.split.map(&:to_i)
puts (1..n).select{|e|(a..b).include?(e.to_s.chars.map(&:to_i).inject(&:+))}.inject(&:+)
入力を受け取るところまでは、解答①とほぼ同じですね。その後の流れを見てみると、
① 整数の各桁の和がa以上b以下であるかとinclude?メソッドで判定する
② ①を通過した整数は、selectメソッドで新しい配列を生成し、その中に追加する
③ 条件に合う整数が出そろったところで、最後尾のinjectメソッドで整数の総和を求め、出力する
ここで使われているメソッドについて簡単にまとめます。
include?メソッド(Rangeクラス)
オブジェクトが範囲内に含まれている時、trueを返します。
#例
print (1..5).include?(4)
=> true
selectメソッド
条件に一致した要素を取得して、新しい配列として返します。
#例
print [1,2,3,4,5].select { |num| num > 3 }
=> [4, 5]
最後に
以上、AtCoder Beginners Selection【Some Sums】を解く中で学んだメソッドをご紹介しました。
もし間違いなどございましたら、ご指摘いただけると嬉しいです。