この記事はGopher道場アドベントカレンダーの14日目の記事です。
はじめに
Gopher道場3期生の@kzkiq2ndです。
道場を卒業してしばらくして、文法練習のために競技プログラミングAtCoderにGoで入門しました。
これまで初心者向けのABC114,ABC115に参加しましたが全問正解はできていません。
次こそD問題を正解しようと練習中です。
本記事はAtCoder Beginner Contestの過去問を解いている中で、どう書けばよいか迷い調べた処理をまとめました。
これからAtCoderを始めるGo入門者の方に役立てるかもしれません。
※最新の初心者向けABC115の問題はこんな感じです。
※Gopher道場すごいおすすめです!
メルペイがGopher道場をサポートする理由 #メルペイなう vol.16 #gopherdojo - mercan(メルカン)
文字列に関する処理
文字列n番目の文字はインデックスで得られる
コードポイントがとれるので、文字にするならstring()関数を通す。
r := "Hello, playground"[1]
fmt.Println(r) // => 101
fmt.Println(string(r)) // => e
文字列n番目の文字の比較はシングルクォート
比較はコードポイントのままで良い。
r := "Hello, playground"[1]
if r == 'e' {
fmt.Println(true) // => true
}
if r == "e" {} // => invalid operation: r == "e" (mismatched types byte and string)
文字コードポイント、runeに関しては以下の記事が参考になりました。
Goのruneを理解するためのUnicode知識 - Qiita
文字列の繰り返しはstrings.Repeat()
stringsパッケージの出番です。
fmt.Println(strings.Repeat("Hello", 3)) // => HelloHelloHello
文字列に含まれるかは strings.Contains()
stringsパッケージ便利。
fmt.Println(strings.Contains("Hello, playground", "Hello")) // => true
数字に関する処理
差の絶対値が欲しい math.Abs()
float64で扱うか、intで扱う作法が必要。
abs := int(math.Abs(float64(-100)))
fmt.Println(abs) // => 100
2値の最小最大 math.Max, math.Min
float64で扱うか、intで扱う作法が必要。
var a, b float64
a, b = 1, 10
fmt.Println(math.Max(a, b)) // => 10
fmt.Println(math.Min(a, b)) // => 1
べき乗 math.Pow()
fmt.Println(math.Pow(2, 16)) // => 65536
fmt.Println(math.Pow10(5)) // => 100000
intスライスの最小最大 sort.Ints()
s := []int{4980, 7980, 6980}
sort.Ints(s) // => [4980 6980 7980]
fmt.Println(s[len(s)-1]) // => 7980 max
fmt.Println(s[0]) // => 4980 min
数字を文字列にする strconv.Itoa(int)
fmt.Println(strconv.Itoa(123)) // => "123"
その他
bool型のゼロ値はfalse
ゼロ値で初期化する習慣づくりに。
var b bool
fmt.Println(b) // => false
スライスの比較はreflect.DeepEqual
戻り値がスライスのテストを書くときに利用。
input := []string{".....", ".#.#.", "....."}
want := []string{"11211", "1#2#1", "11211"}
if got := f(input); !reflect.DeepEqual(got, want) {
t.Fatalf("want is %v, got is %v", want, got)
}
文字列スライスの全探索をrangeで書けるの忘れがち
ぐっとシンプルに書けます。
s := []string{"ABC", "DEF", "GHI"}
for i := range s {
for j := range s[i] {
fmt.Print(string(s[i][j])) // => ABCDEFGHI
}
}
以上になります。
おすすめ文法や良い書き方、間違いの指摘があればお気軽に編集リクエストやメッセージ等お送りください。
おまけA:次に見ると良い資料
Goで始めるAtCoderのススメ(初心者向け) - Qiita
「さぁ始めるぞ!」という方には@syumai さんの入門記事を参考にするのがおすすめです。まずは標準入力が扱えれば戦えます。
AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~ - Qiita
最初に解くのは、公式ページにも掲載されているAtCoder入門者チュートリアル10問がおすすめです。
記事中のサンプルコードはC++ですが、別の方がGoで解いた物もあります。
おまけB:The Go Playground便利
コンテスト中でも簡単な文法確認をしたいときにThe Go Playgroundで実行できるのが便利でした。
全体にいえる事ですが、AtCoderで使えるGo1.6とのバージョン差には注意です。
おまけC:テストファーストで解くAtCoder
Goのテストパッケージを素早く扱う練習にと、問題を解く際に簡単なテストを書いています。
// 標準入力をパース
func main() {
var d int
fmt.Scan(&d)
fmt.Println(eve(d))
}
// 問題の回答
func eve(d int) string {
return "Christmas" + strings.Repeat(" Eve", 25-d)
}
// 回答関数のテスト
func TestEve(t *testing.T) {
d := 22
want := "Christmas Eve Eve Eve"
if got := eve(d); got != want {
t.Fatalf("want is %v, got is %v", want, got)
}
}
回答処理を関数とした簡単なテストですが、
- 手元で回答検証が早く出来る
- テーブルテストで複数パターン検証もできる
- テストを書きながら回答を考える習慣がつく
- 振り返りにテストがついている
こんな感じで、テストファーストを習慣づけるのに良いです。
ただしAtCoderはスピード競技でもあり、テスト書いてるだけ提出が遅くなりスコア伸びは悪そうです。
本番ではテストを使わず、過去問練習でテストを書くのはメリットが多いと思います。
※テストファーストで解いた問題をまとめました。
AtCoder過去問精選10問をGo + テスト付きで解いてみた - Qiita