ちなみに

火曜日の空は僕を押しつぶした。

パターン認識

最近、意識が高まって LeetCode を一日一問ずつやっています。 正直、Easy でもだいぶ苦戦していて、基礎の出来てなさに凹む毎日です。

ところで、現代では ChatGPT というSFチックなサービスが存在します。何かを学ぶときに補助してもらうことで、知の高速道路をより素早く進むことが出来るようになりました。 LeetCodeでの練習でいうと、うまく書けなかったなというときにコードをシンプルに書き直してもらうと学ぶところが多々あります。

今日は本当にクソみたいなコードを書いたので、ちょっとでもヒントを得ようと書き直してもらったのですが、あまりにシンプルなコードになってひっくり返りました。 最初みたときにハルシネーションだろって思ってしまったのですが、よく読むとすごく正しい。

自分は与えられた問題の情報を愚直にコードに落とし込んでしまっていて、今回の問題の本質 = 一定のパターンがあることに気付いていませんでした。 GPT-4o は自分の書いたクソコードをみただけで、そのパターンに気付いてコードに落とし込んでくれたのです。

問題解決の糸口として、なんらかのパターンがないかというのは普段は考えている気がするけど、こういう問題形式でプログラミングするときには頭が回ってなかったので、すごくハッとさせられたのでした。

(もちろん本当のところは同様のコードを大量に見せられていて、ベストな回答を知っていたということだとは思うのだけれど)

おまけ

問題は与えられたローマ数字の文字列を数値に直すというやつでした。

自分の書いたクソみたいにナイーブなコードがこれ。

func romanToInt(s string) int {
    num := 0
    rs := []rune(s)
    for i := 0; i < len(rs); i++ {
        r := rs[i]
        switch r {
        case 'I':
            if i+1 < len(rs) {
                n := rs[i+1]
                if n == 'V' {
                    num += 4
                    i += 1
                    continue
                } else if n == 'X' {
                    num += 9
                    i += 1
                    continue
                }
            }
            num += 1
            continue
        case 'V':
            num += 5
            continue
        case 'X':
            if i+1 < len(rs) {
                n := rs[i+1]
                if n == 'L' {
                    num += 40
                    i += 1
                    continue
                } else if n == 'C' {
                    num += 90
                    i += 1
                    continue
                }
            }
            num += 10
            continue
        case 'L':
            num += 50
            continue
        case 'C':
            if i+1 < len(rs) {
                n := rs[i+1]
                if n == 'D' {
                    num += 400
                    i += 1
                    continue
                } else if n == 'M' {
                    num += 900
                    i += 1
                    continue
                }
            }
            num += 100
            continue
        case 'D':
            num += 500
            continue
        case 'M':
            num += 1000
            continue
        default:
            panic("invalid rune")
        }
    }
    return num
}

ChatGPT が書き直してくれたのがこれ。

func romanToInt(s string) int {
    // ルーンとその値のマッピング
    romanValues := map[rune]int{
        'I': 1,
        'V': 5,
        'X': 10,
        'L': 50,
        'C': 100,
        'D': 500,
        'M': 1000,
    }

    num := 0
    rs := []rune(s)
    for i := 0; i < len(rs); i++ {
        // 現在のルーンの値
        currentValue := romanValues[rs[i]]

        // 次のルーンが存在し、かつその値が現在のルーンの値より大きい場合
        if i+1 < len(rs) && romanValues[rs[i+1]] > currentValue {
            num -= currentValue
        } else {
            num += currentValue
        }
    }

    return num
}