347. 前 K 个高频元素
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
1 <= nums.length <= 105
k 的取值范围是 [1, 数组中不相同的元素的个数]
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的
进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。
1、使用小根堆,将频率小的数据pop,留下的就是k个频率大的数据。
func topKFrequent(nums []int, k int) []int {
// 统计nums的数量
map_num := make(map[int]int)
for _, num := range nums {
map_num[num]++
}
// 创建小根堆,维护小根堆的元素
h := &IHeap{}
heap.Init(h)
for key, val := range map_num {
// 插入元素,如果堆中元素个数大于k,则删除堆顶元素
heap.Push(h, [2]int{key, val})
if h.Len() > k {
heap.Pop(h) // 移除频率最小的元素
}
}
// 结果数组
result := make([]int, k)
for i := k - 1; i >= 0; i-- { // 反向填充结果,确保频率大的元素在前面
result[i] = heap.Pop(h).([2]int)[0]
}
return result
}
// IHeap 构建小根堆,切片里面存储有两个元素的数组,hash存储的kv
type IHeap [][2]int
func (h IHeap) Len() int {
return len(h)
}
func (h IHeap) Less(i, j int) bool {
// 比较value的大小,构建小根堆
return h[i][1] < h[j][1]
}
func (h IHeap) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
}
func (h *IHeap) Push(x interface{}) {
// 类型断言,断言 x 是 [2]int 类型
*h = append(*h, x.([2]int))
}
func (h *IHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[:n-1]
// 返回被移除的元素
return x
}
以上需要注意的就是,“container/heap” 这个包里面已经给我设计好了接口,我们只需要实现这个接口就可以了。
type Interface interface {
sort.Interface
Push(x any) // add x as element Len()
Pop() any // remove and return element Len() - 1.
}
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
在heap中,已经定义好了接口,我们只需要自定义实现这个五个方法,就可以实现我们定义好的功能了。