优先级队列(堆)

例题一

解法(利⽤堆):
算法思路:
其实就是⼀个模拟的过程:
每次从⽯堆中拿出最⼤的元素以及次⼤的元素,然后将它们粉碎;
如果还有剩余,就将剩余的⽯头继续放在原始的⽯堆⾥⾯。
重复上⾯的操作,直到⽯堆⾥⾯只剩下⼀个元素,或者没有元素(因为所有的⽯头可能全部抵消了)
那么主要的问题就是解决:
如何顺利的拿出最⼤的⽯头以及次⼤的⽯头;
并且将粉碎后的⽯头放⼊⽯堆中之后,也能快速找到下⼀轮粉碎的最⼤⽯头和次⼤⽯头;
这不正好可以利⽤堆的特性来实现嘛?
我们可以创建⼀个⼤根堆;
然后将所有的⽯头放⼊⼤根堆中;
每次拿出前两个堆顶元素粉碎⼀下,如果还有剩余,就将剩余的⽯头继续放⼊堆中;
这样就能快速的模拟出这个过程。

例题二

解法(优先级队列):
算法思路:
我相信,看到 TopK 问题的时候,兄弟们应该能⽴⻢想到「堆」,这应该是刻在⻣⼦⾥的记忆。

例题三

解法(堆):
算法思路:
稍微处理⼀下原数组:
a. 我们需要知道每⼀个单词出现的频次,因此可以先使⽤哈希表,统计出每⼀个单词出现的频 次;
b. 然后在哈希表中,选出前 k ⼤的单词(为什么不在原数组中选呢?因为原数组中存在重复的单 词,哈希表⾥⾯没有重复单词,并且还有每⼀个单词出现的频次)
如何使⽤堆,拿出前 k ⼤元素:
a. 先定义⼀个⾃定义排序,我们需要的是前 k ⼤,因此需要⼀个⼩根堆。但是当两个字符串的频次相同的时候,我们需要的是字典序较⼩的,此时是⼀个⼤根堆的属性,在定义⽐较器的时候需要注意!
当两个字符串出现的频次不同的时候:需要的是基于频次⽐较的⼩根堆
当两个字符串出现的频次相同的时候:需要的是基于字典序⽐较的⼤根堆
b. 定义好⽐较器之后,依次将哈希表中的字符串插⼊到堆中,维持堆中的元素不超过 k 个;
c. 遍历完整个哈希表后,堆中的剩余元素就是前 k ⼤的元素

例题四

解法(利⽤两个堆):
算法思路:
这是⼀道关于「堆」这种数据结构的⼀个「经典应⽤」。
我们可以将整个数组「按照⼤⼩」平分成两部分(如果不能平分,那就让较⼩部分的元素多⼀个),较⼩的部分称为左侧部分,较⼤的部分称为右侧部分:
将左侧部分放⼊「⼤根堆」中,然后将右侧元素放⼊「⼩根堆」中;
这样就能在 O(1) 的时间内拿到中间的⼀个数或者两个数,进⽽求的平均数。
如下图所⽰:
于是问题就变成了「如何将⼀个⼀个从数据流中过来的数据,动态调整到⼤根堆或者⼩根堆中,并且保证两个堆的元素⼀致,或者左侧堆的元素⽐右侧堆的元素多⼀个」,为了⽅便叙述,将左侧的「⼤根堆」记为 left ,右侧的「⼩根堆」记为 right ,数据流中来的「数据」记为 x 。其实,就是⼀个「分类讨论」的过程:
1. 如果左右堆的「数量相同」, left.size() == right.size()
a. 如果两个堆都是空的,直接将数据 x 放⼊到 left 中;
b. 如果两个堆⾮空:
i. 如果元素要放⼊左侧,也就是 x <= left.top() :那就直接放,因为不会影响我们制定的规则;
ii. 如果要放⼊右侧
可以先将 x 放⼊ right 中,
然后把 right 的堆顶元素放⼊ left 中 ;
2. 如果左右堆的数量「不相同」,那就是 left.size() > right.size()
a. 这个时候我们关⼼的是 x 是否会放⼊ left 中,导致 left 变得过多:
i. 如果 x 放⼊ right 中,也就是 x >= right.top() ,直接放;
ii. 反之,就是需要放⼊ left 中:
可以先将 x 放⼊ left 中,
然后把 left 的堆顶元素放⼊ right 中 ;
只要每⼀个新来的元素按照「上述规则」执⾏,就能保证 left 中放着整个数组排序后的「左半部 分」, right 中放着整个数组排序后的「右半部分」,就能在 O(1) 的时间内求出平均数。
  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我要满血复活

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

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

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

打赏作者

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

抵扣说明:

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

余额充值