RubyでAtCoder ABC296(A, B, C)を解いてみた

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC296のA, B, Cを解きました。備忘録として解き方をまとめていきたいと思います。

<追記>
いただいたコメントをもとに別解の作成や修正を行いました。コメントしていただきありがとうございます。

# A - Alternately
https://atcoder.jp/contests/abc296/tasks/abc296_a
```ruby:a-296.rb
n = gets.to_i
s = gets.chomp
at = s[0]
for i in 1..n - 1
    if s[i] == at
        puts "No"
        exit
    end
    at = s[i]
end
puts "Yes"
```
```ruby:別解１
n = gets
s = gets.chomp.chars
puts s.each_cons(2).any?{|i, j| i == j} ? "No" : "Yes"
```
```diff_ruby:別解２
n = gets
s = gets.chomp
- puts s.match(/(.)\1/) ? "No" : "Yes"
+ puts s.match?(/(.)\1/) ? "No" : "Yes"
```

```ruby:別解３
n = gets.to_i
s = gets.chomp
puts n.times.all?{ |i| s[i] != s[i + 1]} ? "Yes" : "No"
```
## 解説
まず、atをsの先頭の文字で初期化します。そして、順にs[i]がatと一致しているかどうかを調べていき一致していればNoを出力して終了し、そうでなければatを更新します。最後まで一致するものがなければYesを出力します。

<別解１>
each_consメソッドとarr？メソッドを使って隣り合う文字が異なるかどうかを判定しています。

<別解２>
正規表現を使って解くこともできるようです（難しい...）。

~~正規表現における`.`はメタ文字といい任意の文字が入り記憶されます。~~
<追記>
内容が誤っていました、すいません。
>正規表現の`.`は、改行を除く任意の文字を意味するものであり、これ自体は記憶に関わりません。マッチした部分文字列を記憶するのはキャプチャー`( )`の働きです。

とのことです。

また、`\1`では記憶された文字を参照することができます。
上記コードでは、これらとmatchメソッドを合わせて、`.`の文字と記憶された文字が一致しているかどうかを判定しています。
<追記>
マッチしているかどうかだけを知りたいのでmatchメソッドでなく、match?メソッドで十分です。

<別解３>
all?メソッドを使って隣り合う文字がすべて異なるかどうかを判定しています。

メモ
・[Enumurator](https://docs.ruby-lang.org/ja/3.2/class/Enumerator.html)：クラス、Enumerableモジュールをインクルードしている（Mix-in）。
・[Enumerable](https://docs.ruby-lang.org/ja/3.2/class/Enumerable.html)：モジュール、このモジュール内のメソッドはeachを用いて定義されている。
・[Enumerable#each_cons](https://docs.ruby-lang.org/ja/3.2/method/Enumerable/i/each_cons.html)：`Array.each_cons(num){|v| 処理}`の形で使い、numの数だけ連続する要素を返す。

・正規表現における`.`は任意の文字を表すメタ文字。キャプチャー`( )`により文字は記憶される。\1は後方参照で記憶された文字を参照できる。
・[String#match](https://docs.ruby-lang.org/ja/3.2/method/String/i/match.html)：実際に何が同じなのかを返す。
・[String#match?](https://docs.ruby-lang.org/ja/3.2/method/String/i/match=3f.html)：trueかfalseのみを返す。

# B - Chessboard
https://atcoder.jp/contests/abc296/tasks/abc296_b
```ruby:b-296.rb
# 修正前
str = []
8.times do
    str << gets.chomp
end

arr = *"a".."z"
8.times do|i|
    8.times do|j|
        if str[i][j] == "*"
            puts "#{arr[j]}#{8 - i}"
            exit
        end
    end
end
```
```ruby:b-296.rb
# 修正後
grid = Array.new(8){gets.chomp}.join

i = grid.index("*")
puts "abcdefgh"[i % 8] + "87654321"[i / 8]
```
## 解説
<追記>
コメントで書いていただいたコードを真似してます。コメントありがとうございます。

まとめて1つの文字列とすることで、`*`の位置を特定しています。最後に対応する文字と数字を連結して出力すればOKです。

# C - Gap Existence
https://atcoder.jp/contests/abc296/tasks/abc296_c
```ruby:c-296.rb
# 修正前
n ,x = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)

hash = a.tally
puts hash.any?{|key, val| hash.include?(key + x)} ? "Yes" : "No"
```
```ruby:c-296.rb
# 修正後
n ,x = gets.split.map(&:to_i)
a = gets.split.map(&:to_i).uniq

hash = {}
a.each{|key| hash[key] = true}
puts hash.any?{|key, value| hash.include?(key + x)} ? "Yes" : "No"
# puts a.any?{|i| a.include?(i + x)} ? "Yes" : "No"
# 上記のコードも試しましたが、TLEしてしまいます。連想配列の方が高速なのかな？
```
## 解説
（他の方の提出結果を参考にしました）

まず、連想配列hashにどの要素があるかをもたせます。そして、条件を満たす場合a[i]=x+a[j]であることを利用して判定を行えば条件を満たすものがあるかどうかを判定することができます。

# 終わりに
C問題は愚直に解こうとするとTLEしてしまうので、工夫が必要でした。AtCoder Problemsでdiffを確認したら灰色の真ん中ぐらいだったので「えー」と思いました。得意不得意によって自分の中のdiffは変わりますよね...。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166

# 参考
https://jq-jo.github.io/blog/2017/03/14/ruby-class-instance-module/

https://qiita.com/shizuma/items/4279104026964f1efca6