Leetcode Note: Go - Plus One

Plus One - LeetCode
https://leetcode.com/problems/plus-one/

  • Go 言語で取り組んだメモ

所感

  • 配列の要素を 1つ の数値に統合して +1 し、その結果を配列としてパースして return すれば良さそう

実装準備

func plusOne(digits []int) []int {
    return digits
}

func main() { 
    digits := []int{1,2,3}
    fmt.Println(plusOne(digits))
}

v1

func plusOne(digits []int) []int {
    for i := 0; i < len(digits); i++ {
        if i == len(digits) -1 {
            digits[i]++
        }
    }
    return digits
}
  • 数値を統合してプラスして return するより、ループで最後の要素に +1 した方が計算量が少ないのでは、と実装中に思いついた
  • しかし、これは桁上りが考慮されていないため、不完全

回答

func carryUp(digits []int) []int {
    for i := len(digits) - 1; i >= 0; i-- {
        if digits[i] > 9 {
            digits[i] = 0
            if i != 0 {
                digits[i-1] += 1
            } else {
                digits = append([]int{1}, digits...)
            }
        }
    }
    return digits
}

func plusOne(digits []int) []int {
    digits[len(digits) - 1]++
    digits = carryUp(digits)
    return digits
}
  • 色々修正していって結果は上記のようになった
  • そもそも plusOne の for loop は不要だったので削除
  • 桁上りを行う carryUp 関数を実装
    • 配列を loop して 10 の値があったら桁数を調整する
    • スライスの先頭に要素を追加したい場合に digits = append([]int{1}, digits...) のように、追加したい要素から append に指定するという書き方があった
  • 反省点としては…

    • for loop で i– をする書き方で時間を使ってしまったので、サッと書けるようになりたい所
    • carryUp 関数内で append で digits を操作するので、わざわざ digits を return する必要ないか?と思ったが、そうすると plusOne で append した digits が return できず、これに詰まった

      • append は新しい配列を生成するので、改めて return する必要があった
      • これは append を使わない場合でも、新しい配列を定義すると同じく return が必要
      • 与えられた配列の既存要素を上書きするなら不要

        package main
        
        import "fmt"
        
        func myAppend(x []int) {
        	x = append(x, 2)
        }
        
        func myNewArray(x []int) {
        	x = []int{1, 2, 3}
        }
        
        func myArray(x []int) {
        	x[1] = 3
        }
        
        func main() {
        	x := []int{0}
        	fmt.Println(x) // [0]
        
        	x = append([]int{1}, x...) // 普通に Append する分には問題なし
        	fmt.Println(x) // [1 0]
        
        	myAppend(x) // 別関数内で Append すると、呼び出し元のスライスには影響がない
        	fmt.Println(x) // [1 0]
        
        	myNewArray(x)  // 別関数内で新しく配列を定義しても同様で、呼び出し元に影響は内
        	fmt.Println(x) // [1 3]
        
        	myArray(x) // 別関数内で既存要素を変更すると、呼び出し元の要素に影響する
        	fmt.Println(x) // [1 3]
        }
  • そこそこの可読性を保ちつつ、計算量の少ない実装ができて結構満足度が高かった