面试题答案
一键面试package main
import (
"fmt"
"sort"
)
type BySumAndLen struct {
m map[string][]int
keys []string
}
func (b BySumAndLen) Len() int {
return len(b.keys)
}
func (b BySumAndLen) Less(i, j int) bool {
sumI := 0
for _, v := range b.m[b.keys[i]] {
sumI += v
}
sumJ := 0
for _, v := range b.m[b.keys[j]] {
sumJ += v
}
if sumI != sumJ {
return sumI < sumJ
}
return len(b.m[b.keys[i]]) < len(b.m[b.keys[j]])
}
func (b BySumAndLen) Swap(i, j int) {
b.keys[i], b.keys[j] = b.keys[j], b.keys[i]
}
func sortMapBySumAndLen(m map[string][]int) []string {
var keys []string
for k := range m {
keys = append(keys, k)
}
sorter := BySumAndLen{m, keys}
sort.Sort(sorter)
return sorter.keys
}
时间复杂度分析
- 计算总和:对于每个切片,计算其总和的时间复杂度为 (O(n)),其中 (n) 是切片中元素的个数。假设总共有 (m) 个切片,平均每个切片长度为 (n),那么计算所有切片总和的时间复杂度为 (O(mn))。
- 排序:Go 语言中
sort.Sort
使用的是快速排序,平均时间复杂度为 (O(m \log m)),其中 (m) 是切片的数量。
综合起来,总的时间复杂度为 (O(mn + m \log m))。
空间复杂度分析
- 存储键:我们创建了一个切片来存储所有的键,其空间复杂度为 (O(m)),其中 (m) 是映射中键值对的数量。
- 排序过程:快速排序的空间复杂度在平均情况下为 (O(\log m)),最坏情况下为 (O(m))。
综合起来,总的空间复杂度为 (O(m))。
性能优化
- 预计算总和:在构建
BySumAndLen
结构体时,可以预先计算每个切片的总和并存储起来,这样在Less
方法中就不需要每次都重新计算总和,从而将计算总和的时间复杂度从 (O(mn)) 降低到 (O(m)),整体时间复杂度变为 (O(m + m \log m)),近似为 (O(m \log m))。 - 减少内存分配:尽量减少在
Less
方法中的临时变量分配,例如可以预先分配好存储总和的变量,避免每次调用Less
时都进行内存分配。