Golang | Leetcode Golang题解之第480题滑动窗口中位数

题目:

题解:

Go 复制代码
type hp struct {
    sort.IntSlice
    size int
}
func (h *hp) Push(v interface{}) { h.IntSlice = append(h.IntSlice, v.(int)) }
func (h *hp) Pop() interface{}   { a := h.IntSlice; v := a[len(a)-1]; h.IntSlice = a[:len(a)-1]; return v }
func (h *hp) push(v int)         { h.size++; heap.Push(h, v) }
func (h *hp) pop() int           { h.size--; return heap.Pop(h).(int) }
func (h *hp) prune() {
    for h.Len() > 0 {
        num := h.IntSlice[0]
        if h == small {
            num = -num
        }
        if d, has := delayed[num]; has {
            if d > 1 {
                delayed[num]--
            } else {
                delete(delayed, num)
            }
            heap.Pop(h)
        } else {
            break
        }
    }
}

var delayed map[int]int
var small, large *hp

func medianSlidingWindow(nums []int, k int) []float64 {
    delayed = map[int]int{} // 哈希表,记录「延迟删除」的元素,key 为元素,value 为需要删除的次数
    small = &hp{}           // 大根堆,维护较小的一半元素
    large = &hp{}           // 小根堆,维护较大的一半元素
    makeBalance := func() {
        // 调整 small 和 large 中的元素个数,使得二者的元素个数满足要求
        if small.size > large.size+1 { // small 比 large 元素多 2 个
            large.push(-small.pop())
            small.prune() // small 堆顶元素被移除,需要进行 prune
        } else if small.size < large.size { // large 比 small 元素多 1 个
            small.push(-large.pop())
            large.prune() // large 堆顶元素被移除,需要进行 prune
        }
    }
    insert := func(num int) {
        if small.Len() == 0 || num <= -small.IntSlice[0] {
            small.push(-num)
        } else {
            large.push(num)
        }
        makeBalance()
    }
    erase := func(num int) {
        delayed[num]++
        if num <= -small.IntSlice[0] {
            small.size--
            if num == -small.IntSlice[0] {
                small.prune()
            }
        } else {
            large.size--
            if num == large.IntSlice[0] {
                large.prune()
            }
        }
        makeBalance()
    }
    getMedian := func() float64 {
        if k&1 > 0 {
            return float64(-small.IntSlice[0])
        }
        return float64(-small.IntSlice[0]+large.IntSlice[0]) / 2
    }

    for _, num := range nums[:k] {
        insert(num)
    }
    n := len(nums)
    ans := make([]float64, 1, n-k+1)
    ans[0] = getMedian()
    for i := k; i < n; i++ {
        insert(nums[i])
        erase(nums[i-k])
        ans = append(ans, getMedian())
    }
    return ans
}
相关推荐
sheeta19985 小时前
LeetCode 每日一题笔记 日期:2025.03.24 题目:2906.构造乘积矩阵
笔记·leetcode·矩阵
不会聊天真君6479 小时前
基础语法·中(golang笔记第二期)
开发语言·笔记·golang
zdl68610 小时前
搭建Golang gRPC环境:protoc、protoc-gen-go 和 protoc-gen-go-grpc 工具安装教程
开发语言·后端·golang
老鼠只爱大米11 小时前
LeetCode经典算法面试题 #295:数据流的中位数(双堆法、有序列表、平衡树等多种实现方案详解)
算法·leetcode·优先队列··数据流·中位数·java 面试题
x_xbx11 小时前
LeetCode:215. 数组中的第K个最大元素
数据结构·算法·leetcode
FatHonor12 小时前
【golang学习之旅】使用VScode安装配置Go开发环境
vscode·学习·golang
进击的荆棘12 小时前
优选算法——分治
数据结构·算法·leetcode·分治
木井巳13 小时前
【递归算法】找出所有子集的异或总和再求和
java·算法·leetcode·决策树·深度优先
ん贤13 小时前
AI大模型落地系列:一文读懂 Eino 的 Memory 与 Session(持久化对话)
大数据·ai·golang·eino
Aaswk14 小时前
回溯算法的本质理解
c语言·算法·leetcode·力扣·剪枝