LoginSignup
39
20

More than 5 years have passed since last update.

AtCoder初心者が迷って調べたGo文法

Last updated at Posted at 2018-12-14

この記事は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

参考:Go言語で文字列を処理する

数字に関する処理

差の絶対値が欲しい 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

参考:ゼロ値を使おう #golang - Qiita

スライスの比較はreflect.DeepEqual

戻り値がスライスのテストを書くときに利用。

ABC075Bのテストから抜粋
    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のテストパッケージを素早く扱う練習にと、問題を解く際に簡単なテストを書いています。

ABC115A回答から抜粋
// 標準入力をパース
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)
    }
}

回答処理を関数とした簡単なテストですが、

  1. 手元で回答検証が早く出来る
  2. テーブルテストで複数パターン検証もできる
  3. テストを書きながら回答を考える習慣がつく
  4. 振り返りにテストがついている

こんな感じで、テストファーストを習慣づけるのに良いです。

ただしAtCoderはスピード競技でもあり、テスト書いてるだけ提出が遅くなりスコア伸びは悪そうです。
本番ではテストを使わず、過去問練習でテストを書くのはメリットが多いと思います。

※テストファーストで解いた問題をまとめました。
AtCoder過去問精選10問をGo + テスト付きで解いてみた - Qiita

39
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
20