go使用标准库实现堆,及前K个高频元素,滑动窗口的最大值解法

本文介绍了如何在Go语言中使用堆数据结构,包括大顶堆的实现,并通过两个LeetCode算法题(前K个高频元素、滑动窗口最大值)展示了堆的应用。首先定义堆结构体,实现`container/heap`的接口,接着初始化堆并进行操作。在实际问题中,堆能高效地找到最大或最小元素,对于动态数据集尤其有用。
摘要由CSDN通过智能技术生成

0.前言

堆是一种树形数据结构(完全二叉树),分为大顶堆和小顶堆,顾名思义,大顶堆就是堆顶(第一个元素)始终存放的是这组元素中的最大元素,小顶堆就是堆顶元素是最小元素。如果需要从一组对象中查找最大值最小值,且元素会动态增加,使用堆能够高效率的完成需求。GO中标准库提供了heap的功能,一起看看如何使用吧。

1.GO语言中的Heap包使用方法

使用Heap,主要分为三步:

  • 定义堆结构体
  • 实现heap中Interface接口
  • 初始化堆并使用堆

直接上代码:

package main

import (
	"container/heap"
	"fmt"
)
//定义堆结构体
type HeapInts []int

// 实现Interface接口
// 其中包含 sort中的Interface接口 和push、pop接口
// 注意 push和pop接口的接收者必须是指针
func (h HeapInts) Len() int {
	return len(h)
}
//此处是大顶堆,如果是 < 即变成小顶堆
func (h HeapInts) Less(i, j int) bool {
	return h[i] > h[j]
}

func (h HeapInts) Swap(i, j int) {
	h[i],h[j]=h[j],h[i]
}

func (h *HeapInts) Push(x interface{}) {
	*h =append(*h,x.(int))
}

func (h *HeapInts) Pop() interface{} {
	temp:=(*h)[len(*h)-1]
	*h=(*h)[:len(*h)-1]
	return temp
}
func main()  {
	var h HeapInts
	h=append(h,2,1,3)
	fmt.Println(h)
    //初始化堆
	heap.Init(&h)
	fmt.Println(h)
    //向堆中插入元素
	heap.Push(&h,9)
	heap.Push(&h,5)
	fmt.Println(h)
    //弹出堆顶元素
	x:=heap.Pop(&h)
	fmt.Println(x)
	fmt.Println(h)
}

2.一些使用堆解决的算法题

leetcode上有很多可以用堆解决的题目,这里放出两题:

347. 前 K 个高频元素 - 力扣(LeetCode)

239. 滑动窗口最大值 - 力扣(LeetCode)

2.1 前K个高频元素

在本题中,堆中每个节点存储一个数的值和数的出现次数,出现次数用于排序,值用于得到答案。

首先使用map记录所有元素的出现次数,然后根据上述的构建堆的步骤构建堆,用于存放map中的数据,此处构建的是大顶堆,最后Pop出K个元素,即是答案,代码如下:

type mm  struct {
	k int
	v int
}
type ms []mm

func (m ms) Len() int {
	return len(m)
}
//根据v值进行排序
func (m ms) Less(i, j int) bool {
	return m[i].v > m[j].v
}

func (m ms) Swap(i, j int) {
	m[i],m[j]=m[j],m[i]
}

func (m *ms) Push(x interface{}) {
	 *m=append(*m,x.(mm))
}

func (m *ms) Pop() interface{} {
	temp:= (*m)[len(*m)-1]
	*m=(*m)[:len(*m)-1]
	return temp
}

func topKFrequent(nums []int, k int) []int {
	var result []int
	m:=make(map[int]int)
	for _,v:=range nums{
		m[v]++
	}

	var h ms
	for k,v:=range m{
		h=append(h,mm{k: k,v: v})
	}
    //初始化堆
	heap.Init(&h)
    //得到答案
	for i:=0;i<k;i++{
		result=append(result,heap.Pop(&h).(mm).k)
	}
	return result
}

2.2 滑动窗口的最大值

在本题中,堆的数据结构中,每个节点存储一个数的下标和数的值。值用于排序,下标用于判断是否在滑动窗口之中。具体流程如下:

  • 首先使用第一个滑动窗口的值来构建堆。
  • 往右移动一格窗口,将新加入的节点入堆。然后对堆顶元素进行检测(使用k),如果此元素处于滑动窗口中,保存到结果,继续移动窗口;如果不处于窗口中,弹出元素,检测下一个堆顶元素,直到找到一个堆中元素。
  • 重复第二步直到遍历完整个数组,返回结果

代码如下:

type mm  struct {
	k int
	v int
}
type ms []mm

func (m ms) Len() int {
	return len(m)
}

func (m ms) Less(i, j int) bool {
	return m[i].v > m[j].v
}

func (m ms) Swap(i, j int) {
	m[i],m[j]=m[j],m[i]
}

func (m *ms) Push(x interface{}) {
	 *m=append(*m,x.(mm))
}

func (m *ms) Pop() interface{} {
	temp:= (*m)[len(*m)-1]
	*m=(*m)[:len(*m)-1]
	return temp
}

func maxSlidingWindow(nums []int, k int) []int {
	var h ms
	var result []int
	for i := 0; i < k; i++ {
		h=append(h,mm{k: i,v: nums[i]})
	}
	heap.Init(&h)
	result=append(result,h[0].v)
	for i := k; i < len(nums); i++ {
		heap.Push(&h, mm{k: i, v: nums[i]})
		for {
			if h[0].k >= i - k + 1 {
				result = append(result, h[0].v)
				break
			}else{
				heap.Pop(&h)
			}
		}
	}
	return result
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨雨不怕雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值