Leetcode Note: Go - Add Binary
Add Binary - LeetCode
https://leetcode.com/problems/add-binary/
- Go 言語で取り組んだメモ
所感
- パッと見た感じ、ただの文字列連携かと思ったが 2進数 としての加算が必要
- 引数の string をパースして加算処理を行い、文字列にして return する必要がある
- パース
- for loop するしか無さそう
- 加算処理
- 桁上りを考慮する必要あり
- 文字列にして return
- itoa すれば OK
実装準備
func addBinary(a string, b string) string {
return "Hello"
}
func main() {
a := "11"
b := "1"
fmt.Println(addBinary(a, b))
}
v1
func addBinary(a string, b string) string {
// MAX_LENGTH := 5
// convert to int array with zero fill
intA := make([]int, len(a))
intB := make([]int, len(b))
for i := len(a) - 1; i >= 0; i-- {
// for i := 0; i < len(a); i++ {
if s, err := strconv.Atoi(string(a[i])); err == nil {
intA[i] = s
fmt.Println(s)
}
}
for i := len(b) - 1; i >= 0; i-- {
if s, err := strconv.Atoi(string(b[i])); err == nil {
intB[i] = s
}
}
// for len(intA) != 5 {
// intA = append(make([]int, 1), intA)
// }
// for len(intB) != 5 {
// intB = append([]int{0}, intB)
// }
// この計算でやるなら zero fill が必要
maxLength := len(a)
if len(a) < len(b) {
maxLength = len(b)
}
fmt.Println(intA, intB, maxLength)
// sum
sum := make([]int, maxLength)
carry := false // carry up flag
for i := maxLength - 1; i >= 0; i-- {
if len(intA) > i {
sum[i] += intA[i]
}
if len(intB) > i {
sum[i] += intB[i]
}
if sum[i] == 2 {
sum[i] = 0
carry = true
// for j := i + 1; j < maxLength; j++ {
// if sum[j] == 0 {
// sum[j]++
// } else if sum[j] == 1 {
// sum[j] = 0
// }
// }
}
}
// carry up
if carry {
sum = append(sum, 1)
}
// convert string
str := ""
for i := len(sum) - 1; i >= 0; i-- {
str += strconv.Itoa(sum[i])
}
fmt.Println(sum, carry, str)
return str
}
- 計算について考える
- a = 1010
- b = 1011
- ans = 10101
- 計算するときは逆順の方が都合が良さそう、そしてできればゼロ埋めしたい
- 00101
- 01101
- 10101
- 頭が働かず実装まで至らず・・・
- そもそも for loop ありすぎでヤバい
回答
go simple 0ms - LeetCode Discuss
https://leetcode.com/problems/add-binary/discuss/1031983/go-simple-0ms
func addBinary(a string, b string) string {
l1 := len(a) - 1
l2 := len(b) - 1
c := 0 // carry
rs := 0
var str strings.Builder
for l1 >= 0 || l2 >= 0 {
rs = c
if l1 >= 0 {
rs += convBinary(a[l1])
}
if l2 >= 0 {
rs += convBinary(b[l2])
}
c = rs >> 1
rs = rs & 1
if rs == 1 {
str.WriteByte('1')
} else {
str.WriteByte('0')
}
l1 -= 1
l2 -= 1
}
if c == 1 {
str.WriteByte('1')
}
var str2 strings.Builder
t := str.String()
// reverse str
for i := len(t) - 1; i >= 0; i -= 1 {
str2.WriteByte(t[i])
}
return str2.String()
}
func convBinary(c byte) int {
if c == '1' {
return 1
}
return 0
}
- 同じようなアプローチの回答を読んだ
- for loop のループで複数条件をつけるやり方があったか・・・
for l1 >= 0 || l2 >= 0 {
- 2進数を扱う問題だったのでビット演算子の出番だったのも気がつけず
c = rs >> 1
- strings.Builder で文字列の連結が行える
- Atoi は error も return するのに Iota は error を return しないのは何でだろう?
- 追記:
- Itoa の場合、文字列変換に失敗する数値は存在しない
- Aoti の場合、数値変換に失敗する文字列は存在する。例えば aaa とか
- なので冷静に考えたら当たり前だった
- 追記:
- アプローチは大きく間違っていなかったものの、標準ライブラリや演算子のボキャブラリーが不足していた。あと疲れであまり頭が働かなかった。
- アルゴリズムの学習も必要だが、実際に必要となるコーディング力をつけるためには標準ライブラリなど組み込みの機能を色々把握しておくのが大事そう