由leetcode引发的fmt.Sprintf函数思考
刷leetcode时,发现直接使用"+“拼接字符串与使用fmt.Sprintf函数进行拼接,用例执行时间相差28ms(针对发现问题的题目)。所以需要打开fmt.Sprintf函数流程,观察其到底进行了哪些操作。
使用fmt.Sprintf进行字符串拼接,代码如下:
func getFolderNames(names []string) []string {
nameMap := make(map[string]int64)
for i := range names {
if v, ok := nameMap[names[i]]; ok {
count := v
var tmp string
for ; ok; count++ {
tmp = names[i] + fmt.Sprintf("(%d)", count)
_, ok = nameMap[tmp]
}
nameMap[names[i]] = count
nameMap[tmp] = 1
names[i] = tmp
continue
}
nameMap[names[i]] = 1
}
return names
}
对应耗时如下:
通过分析,解题思路是最优的,在方法上不会有耗时的提高。分析当前耗时最小代码,发现与自己提交代码的结构相同,最大的区别为当前最优代码中字符串拼接使用了+
而非fmt.Sprintf函数。当前最优代码如下:
func getFolderNames(names []string) []string {
res := []string{}
mp := map[string]int{}
for _, name := range names {
str := name
for mp[str] > 0 {
str = name + "(" + strconv.Itoa(mp[name]) +")"
mp[name]++
}
mp[str]++
res = append(res, str)
}
return res
}
使用+
直接拼接字符串代码:
func getFolderNames(names []string) []string {
nameMap := make(map[string]int64)
for i := range names {
if v, ok := nameMap[names[i]]; ok {
count := v
var tmp string
for ; ok; count++ {
tmp = names[i] + "(" + strconv.Itoa(int(count)) + ")"
_, ok = nameMap[tmp]
}
nameMap[names[i]] = count
nameMap[tmp] = 1
names[i] = tmp
continue
}
nameMap[names[i]] = 1
}
return names
}
对应耗时:
使用+
连接后,耗时减少28ms,且超越了当前最小耗时,可见fmt.Sprintf确实为问题关键。
fmt.Sprintf流程中,涉及到字符的copy操作(将string拷贝到buf),且需要逐个对传入的string byte解析,判断%
动词。
直接使用+
拼接,仅涉及字符拷贝,没有动词的解析流程,当拼接字符串比较简单时,可使用直接拼接代替fmt.Sprintf。