这个问题来自a little simple problem from LeetCode。
此问题与LeetCode问题本身无关。但这与解决此LeetCode问题的两种方法有关,两种方法仅在map
的类型上有所不同。
map[byte]int
的第一种方法:func romanToInt(s string) int {
m := map[byte]int{
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000,
}
result := 0
length := len(s)
last_element := length - 1
for i := 0; i < last_element; i++ {
current := m[s[i]]
next := m[s[i+1]]
if current < next {
result -= current
} else {
result += current
}
}
result += m[s[last_element]]
return result
}
如何通过LeetCode在线判断:
✔ Accepted
✔ 3999/3999 cases passed (16 ms)
✔ Your runtime beats 100 % of golang submissions
✔ Your memory usage beats 22 % of golang submissions (3 MB)
map[string]int
的第二种方法:func romanToInt(s string) int {
m := map[string]int{
"I": 1,
"V": 5,
"X": 10,
"L": 50,
"C": 100,
"D": 500,
"M": 1000,
}
result := 0
length := len(s)
last_element := length - 1
for i := 0; i < last_element; i++ {
current := m[string(s[i])]
next := m[string(s[i+1])]
if current < next {
result -= current
} else {
result += current
}
}
result += m[string(s[last_element])]
return result
}
如何通过LeetCode在线判断:
✔ Accepted
✔ 3999/3999 cases passed (16 ms)
✔ Your runtime beats 100 % of golang submissions
✔ Your memory usage beats 100 % of golang submissions (3 MB)
一些对在线评估的评价:
我在1小时的时间间隔内运行了这两个版本10次以上。他们在memory usage
达到了22%vs. 100%。
我的期望:
我认为使用map[byte]int
的第一个应该更快并且节省内存。
为什么更快:
在第二个版本中,我每次必须将rune
强制转换为string
。
(但是compiler explorer告诉我这没什么大不同。)
为什么要节省内存:
因为byte
比string
更轻。
最后一个问题:
为什么memory usage
上有区别?
为什么我的期望是错误的?
答案 0 :(得分:2)
以您的代码romanToIntStr
和romanToIntByt
为基准。 romanToIntStr
和romanToIntByt
之间的差异不明显。您的代码romanToIntStr
和romanToIntByt
效率不高。参见romanToIntArr
。
输出:
$ go test roman2int_test.go -bench=. -benchmem
BenchmarkRomanToIntStr-8 2725520 440 ns/op 0 B/op 0 allocs/op
BenchmarkRomanToIntByt-8 2377992 499 ns/op 0 B/op 0 allocs/op
BenchmarkRomanToIntArr-8 25643797 42.3 ns/op 0 B/op 0 allocs/op
roman2int_test.go
:
package main
import "testing"
func romanToIntStr(s string) int {
m := map[string]int{
"I": 1,
"V": 5,
"X": 10,
"L": 50,
"C": 100,
"D": 500,
"M": 1000,
}
result := 0
length := len(s)
last_element := length - 1
for i := 0; i < last_element; i++ {
current := m[string(s[i])]
next := m[string(s[i+1])]
if current < next {
result -= current
} else {
result += current
}
}
result += m[string(s[last_element])]
return result
}
func romanToIntByt(s string) int {
m := map[byte]int{
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000,
}
result := 0
length := len(s)
last_element := length - 1
for i := 0; i < last_element; i++ {
current := m[s[i]]
next := m[s[i+1]]
if current < next {
result -= current
} else {
result += current
}
}
result += m[s[last_element]]
return result
}
func romanToIntArr(s string) int {
m := [256]int{
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000,
}
result := 0
last := len(s) - 1
for i := 0; i < last; i++ {
current := m[(s[i])]
next := m[(s[i+1])]
if current < next {
result -= current
} else {
result += current
}
}
result += m[(s[last])]
return result
}
var bench1942 = "MCMXLII"
func BenchmarkRomanToIntStr(b *testing.B) {
for N := 0; N < b.N; N++ {
romanToIntStr(bench1942)
}
}
func BenchmarkRomanToIntByt(b *testing.B) {
for N := 0; N < b.N; N++ {
romanToIntByt(bench1942)
}
}
func BenchmarkRomanToIntArr(b *testing.B) {
for N := 0; N < b.N; N++ {
romanToIntArr(bench1942)
}
}