#はじめに
RubyでAtCoderをはじめました。
これが面白くてどハマりしてしまい、プログラミングというものの面白さが心の底から分かった瞬間でした。
さて、僕はプログラマではないのですが、
AtCoderを始めるにあたって、知っておいた方が良いTIPSをまとめました。
以下を参照にAtCoderに挑むことにより、なんとか戦えると思います。
AtCoderのアルゴリズムの勉強を通して
Rubyの面白さ、プログラミングの面白さを伝わるといいと思います。
僕は、AとBが普通に解けて、たまにCが解けるので、
以下を見て応用すれば多分同じレベルになるはず。。
謎のアルゴリズムや公式を除けば、
基本は全て以下の応用のハズです。
###入力した文字列を分割する(失敗例)
gets.split('')
aaa
=> ["a", "a", "a", "\n"]
/nが入っちゃってますね。
###入力した文字列を分割する(成功例)
gets.chomp.split('')
aaa
=> ["a", "a", "a"]
chompを入れたらいい感じに分割できました。
###数字を入力する方法(失敗例)
gets.chomp
1
=> "1"
入力が文字列になっていますね。
###数字を入力する方法(成功例)
gets.to_i
1
=> 1
getsは文字列で入力されます。
###数字にした配列を入力aする方法
gets.split.map(&:to_i)
1 2 3
=> [1, 2, 3]
入力は、数字ごとにスペースを入れてください。
###入れ子の配列を複数作る方法
3.times.map{gets.split.map(&:to_i)}
1 2 3
1 2 3
1 2 3
=> [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
複数の数字が入った入れ子構造の配列ができました。
###1つの入力方法+それをN回繰り返して、入力値の配列を作る方法
N = gets.to_i
3
=> 3
b = N.times.map{gets.to_i}
1
2
3
=> [1, 2, 3]
偶数か奇数か判別する方法
a = 2
=> 2
a.even?
=> true
a.odd?
=> false
even?は偶数か判別して
odd?は奇数か判別します。
###変数の長さを確認する
a = "aaaa"
=> "aaaa"
a.size
=> 4
a.length
=> 4
a = [1,2]
=> [1, 2]
a.size
=> 2
a.length
=> 2
sizeとlengthは一緒ですね。
また、文字列も配列もいけます。
###数値の絶対値を取得する
a = -10
=> -10
a
=> -10
a.abs
=> 10
###三項演算子をかく
if true
puts "Yes"
else
puts "No"
end
#上記は一行で書ける
puts true ? "Yes": "No"
これはA問でよく見かけるので覚えておきましょう!
###配列の中の最大値、最小値を出力する
a = [0, 1 ,2, 3]
=> [0, 1, 2, 3]
a.min
=> 0
a.max
=> 3
###配列の中で重複をなくす
a = [1, 1, 2, 2, 3]
=> [1, 1, 2, 2, 3]
a.uniq
=> [1, 2, 3]
###配列の中の合計値を出力する
a = [1, 1, 2, 2, 3]
=> [1, 1, 2, 2, 3]
a.sum
=> 9
a.inject(:+)
=> 9
#備考:掛け算は以下
a.inject(:*)
=> 12
sumとinjectどっちでも良いです。
Ruby2.3.3系だとsum使えないかも!
###配列の末尾に追加する
a = []
=> []
a << 1
=> [1]
a << 2
=> [1, 2]
a << 3
=> [1, 2, 3]
###配列の末尾を削除する
a = [1,2,3]
=> [1, 2, 3]
a.delete_at(-1)
=> 3
a
=> [1, 2]
どの配列の位置も指定できますので便利
###配列の指定の数字を削除
a = [1,2,3]
=> [1, 2, 3]
a.delete(1)
=> 1
a
=> [2, 3]
a = [1,1,2,3]
=> [1, 1, 2, 3]
a.delete(1)
=> 1
a
=> [2, 3]
delete_atとの違いで書きましたが、
指定の数字を削除するのはあまりないかも
uniqを使って重複削除はよく見かけるけれど
###配列の末尾を指定する
a = [1, 1, 2, 2, 3]
=> [1, 1, 2, 2, 3]
a[-1]
=> 3
###指定した番号の配列を取り出す
#5番目を取り出す
n = 5
=> 5
a = [1, 1, 2, 2, 3]
=> [1, 1, 2, 2, 3]
a[n]
=> nil
a[n - 1]
=> 3
配列は0から始まるので-1しなくてはいけませんね。
###配列のある値になったときにループから抜ける
a = [1, 2, 3, 4]
a.each do |i|
if i == 2
puts i
break
end
end
ちなみにBreakとReturnの違いは、ループから抜けるかメソッドから抜けるかの違いです。
Returnはメソッドの中でしか使えません。
###配列の要素の全てが真のときtrueを返す方法
a = [2,2,2,2]
=> [2, 2, 2, 2]
a.all?{|n| n.even?}
=> true
a
=> [2, 2, 2, 2]
a.all?{|n| n == 2}
=> true
a = [2,2,2,3]
=> [2, 2, 2, 3]
a.all?{|n| n == 2}
=> false
配列の要素全てが偶数なので真を返します。
###配列をソート + 昇順から降順へ変更
a = [3,1,2]
=> [3, 1, 2]
a.sort
=> [1, 2, 3]
a.sort.reverse
=> [3, 2, 1]
#ついでに配列に入った文字列も。。
a = [ "aaa", "ccc","bbb"]
=> ["aaa", "ccc", "bbb"]
a.sort
=> ["aaa", "bbb", "ccc"]
a.sort.reverse
=> ["ccc", "bbb", "aaa"]
結構見る
###配列のはじめの要素を削除する
a = [5,6,7]
=> [5, 6, 7]
a.drop(1)
=> [6, 7]
#破壊的ではないようです。
a
=> [5, 6, 7]
a.drop(1)
=> [6, 7]
a.drop(2)
=> [7]
a.drop(3)
=> []
dropは破壊的ではない模様
###配列のはじめの要素を取り出す
a[0]
=> 5
a.shift
=> 5
#↑同じ?
a = [5,6,7]
=> [5, 6, 7]
a.shift
=> 5
a.shift
=> 6
a.shift
=> 7
a = [5,6,7]
=> [5, 6, 7]
a[0]
=> 5
a[0]
=> 5
shift は破壊的のようですね。
同じだと思ってました。
###ある値の時にカウントする方法
a = [1, 2, 3, 4]
count = 0
a.each do |i|
if i == 1
count += 1
end
end
puts count
=>1
###ある値で割り切れる時の条件分岐
k = 2
a, b = [1, 3]
(a..b).each do |c|
if c % k == 0
puts 'OK'
break
end
if c == b
puts 'NG'
end
end
##trueまでループし続ける方法
x = 2
yen = 100
count = 0
while yen > x do
yen += yen / 100
count = count + 1
end
puts count
whileはtrueであり続けかぎりループします。
条件式が必要なく、自分でBreakで
抜けて終了する場合は、loop do ...endを使いましょう!
もちろんwhile true do ...endでも良いです。
###配列をくっつけて文字列にする
a = ["a", "b", "c", "d"]
=> ["a", "b", "c", "d"]
a.join
=> "abcd"
###配列をくっつけて文字列にした後に、指定の文字がいくつあるか探す
a = ["a","b","a","b","a"]
=> ["a", "b", "a", "b", "a"]
a.join
=> "ababa"
a.join.scan("ab")
=> ["ab", "ab"]
#さらに"ab"の個数を取り出す。
a.join.scan("ab").length
=> 2
scanって結構使えそう。。
###配列のブロック(一回ごとに繰り返す値)の配列の中身とインデックスを指定
c = gets.chomp
alf = []
("a".."z").each do |i|
alf << i
end
#配列の中身とインデックスをブロックとして指定
alf.each_with_index do |k, i|
if k == c
puts alf[i+1]
break
end
end
kのみだと、配列の中身"a", "b"・・・"z"を取り出すことになるので
インデックスを指定できないんですよね。
each.with.indexを使って|k, i|とすると
iに配列のインデックスを指定できます。
alf[0]の0のことですね。実際の配列の中身がkです。
###1次元、2次元配列を作る方法
a = Array.new(3)
=> [nil, nil, nil]
a = Array.new(3).map{Array.new(3, 0)}
=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
a[0][1] = 1
=> 1
a
=> [[0, 1, 0], [0, 0, 0], [0, 0, 0]]
a[2][1] = 1
=> 1
a
=> [[0, 1, 0], [0, 0, 0], [0, 1, 0]]
a[2][0] = 1
=> 1
a
=> [[0, 1, 0], [0, 0, 0], [1, 1, 0]]
2次元になるとややこしい
###ある文字列を何回か繰り返す。
a = 2
=> 2
b = 3
=> 3
a.to_s * b
=> "222"
数字で入力したaの入力を文字列に変換し、bで3回繰り返しています。
###数字の切り捨て、繰り上げ、四捨五入
a = 1.4
=> 1.4
a.floor
=> 1
a.ceil
=> 2
a.round
=> 1
a =1.5
=> 1.5
a.floor
=> 1
a.ceil
=> 2
a.round
=> 2
###数字の最大公約数、最小公約数
#最大公約数
4.gcd(2)
=> 2
4.gcd(4)
=> 4
4.gcd(6)
=> 2
#最小公倍数
4.lcm(2)
=> 4
4.lcm(4)
=> 4
4.lcm(6)
=> 12
putsで出力するかpで出力するかprintで出力するか
結論を先に言うとputsが良いです。
pは""がついてしまって答えが合いません。
a = "aaa"
=> "aaa"
p a
"aaa"
=> "aaa"
puts a
aaa
=> nil
print a
aaa=> nil
###indexメソッドである値のインデックスを取得する
#文字列
a = ["3","4"]
=> ["3", "4"]
a
=> ["3", "4"]
a.index("3")
=> 0
a.index("4")
=> 1
##応用
###配列の掛け算
n = gets.to_i
a = gets.split.map(&:to_i)
sum = 1
#基本はeachで回すが、掛け算の中に0があることに注意
a.each do |i|
if i == 0
sum = 0
break
end
#大きい数字のときはsum <=〇〇をしよう!
sum *= i if sum <= 〇〇
end
###小数点にするときto_fだと誤差が生まれるのでto_dを使う
require 'bigdecimal'
require 'bigdecimal/util'
l = gets.chomp.split(" ")
a = l[0].to_i
#to_fにしたら誤差が生まれるようで
#答えが合わない場合がある。
b = l[1].to_d
puts (b * a).floor
###素因数分解をする
require 'prime'
a = 100
=> 100
n = a.prime_division
=> [[2, 2], [5, 2]]
#[[2, 2], [5, 2]]は "(2**2) * (5**2) = 100"ということ
#2次元配列なので要素を2つ指定
n.each do |i, k|
puts i
puts k
end
2
2
5
2
=> [[2, 2], [5, 2]]
###ある配列に於ける全てのパターンを取得する(順列)
n = 3
=> 3
a = [1,2,3]
=> [1, 2, 3]
a.permutation(n).to_a
=> [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
めっちゃ便利!
###文字列の中の指定文字を複数回削除する
n = "testrestdest"
=> "testrestdest"
a
=> ["test", "rest", "pest", "dest"]
a.each do |i|
n.gsub!(/#{i}/, '')
end
n
=> ""
全て消えた
gsub!で破壊的にしています。
###配列を検索しないで解く
#Atcoder149B
#https://atcoder.jp/contests/abc149/tasks/abc149_b
a,b,k = gets.chomp.split.map(&:to_i)
k.times do
if a >= 1
a = a - 1
elsif b >= 1
b = b- 1
elsif a = 0 && b = 0
end
end
puts "#{a} #{b}"
#タイムオーバー
a, b, k = gets.split().map(&:to_i)
if a >= k
puts "#{a-k} #{b}"
elsif a+b <= k
puts "#{0} #{0}"
else
puts "#{0} #{b-(k-a)}"
end
#OK
###数直線の時は絶対数を意識しよう!
aとbははじめの座標
a = 1
=> 1
a = -2
=> -2
a - b
=> -5
(a - b).abs
=> 5
###1次関数で、入力値【角度】から元の位置に戻ってくるような値
x = gets.to_i
puts 360.lcm(x) / x
360度で割れる数なら普通に割れば良いのですが、
360度で割り切れない値だと360度の最小公倍数を求めて
割る必要があるみたいです。