设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。
你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。
int k = 3; int[] arr = [4,5,8,2]; KthLargest kthLargest = new KthLargest(3, arr); kthLargest.add(3); // returns 4 kthLargest.add(5); // returns 5 kthLargest.add(10); // returns 5 kthLargest.add(9); // returns 8 kthLargest.add(4); // returns 8
这道题我们可以想到使用优先队列来做,优先队列的长度为K,按照从小到大排序,那么取出第K大的就是取出下标为0的值
首先我们构造一个小顶堆的数据结构
type KthLargest struct { PriorityQueue []int //优先队列 Size int //小顶堆的容量 }
func Constructor(k int, nums []int) KthLargest { var ks KthLargest ks.Size = k for index := 0; index < len(nums); index++ { ks.Add(nums[index]) } return ks } func (this *KthLargest) Add(val int) int { if len(this.PriorityQueue) < this.Size { this.PriorityQueue = append(this.PriorityQueue, val) } else if this.PriorityQueue[0] <= val { this.PriorityQueue = this.PriorityQueue[1:] this.PriorityQueue = append(this.PriorityQueue, val) } sort.Ints(this.PriorityQueue) return this.PriorityQueue[0] }
这里是一个耗时的做法,因为这里每次添加元素的时候,我们都会去排序,把堆内元素最小的放在最前
而我们可以通过实现golang中的堆的几个接口来自定义我们的堆类型
type intHeap []int //下面几个方法是实现head的接口 func (h intHeap) Len() int { return len(h) } func (h intHeap) Less(i, j int) bool { return h[i] < h[j] } func (h intHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } func (h *intHeap) Push(x interface{}) { // Push 使用 *h,是因为 // Push 增加了 h 的长度 *h = append(*h, x.(int)) } func (h *intHeap) Pop() interface{} { // Pop 使用 *h ,是因为 // Pop 减短了 h 的长度 res := (*h)[len(*h)-1] *h = (*h)[:len(*h)-1] return res }
实现了之后,我们就可以非常简单和快捷的操作堆了
type KthLargest struct { k int heap intHeap } // Constructor 创建 KthLargest func Constructor(k int, nums []int) KthLargest { h := intHeap(nums) heap.Init(&h) for len(h) > k { heap.Pop(&h) } return KthLargest{ k: k, heap: h, } } // Add 负责添加元素 func (kl *KthLargest) Add(val int) int { heap.Push(&kl.heap, val) if len(kl.heap) > kl.k { heap.Pop(&kl.heap) } return kl.heap[0] }