最大栈
最大栈介绍
直接参考Leetcode上895题:895. 最大频率栈
实现 FreqStack
,模拟类似栈的数据结构的操作的一个类。
FreqStack
有两个函数:
push(int x)
,将整数x
推入栈中。pop()
,它移除并返回栈中出现最频繁的元素。- 如果最频繁的元素不只一个,则移除并返回最接近栈顶的元素。
示例:
1 | 输入: |
提示:
- 对
FreqStack.push(int x)
的调用中0 <= x <= 10^9
。 - 如果栈的元素数目为零,则保证不会调用
FreqStack.pop()
。 - 单个测试样例中,对
FreqStack.push
的总调用次数不会超过10000
。 - 单个测试样例中,对
FreqStack.pop
的总调用次数不会超过10000
。 - 所有测试样例中,对
FreqStack.push
和FreqStack.pop
的总调用次数不会超过150000
。
问题分析
这种设计数据结构的问题,主要是要搞清楚问题的难点在哪里,然后结合各种基本数据结构的特性,高效实现题目要求的 API。
那么,我们仔细思考一下 push
和 pop
方法,难点如下:
1、每次 pop
时,必须要知道频率最高的元素是什么。
2、如果频率最高的元素有多个,还得知道哪个是最近 push
进来的元素是哪个。
为了实现上述难点,我们要做到以下几点:
1、肯定要有一个变量 maxFreq
记录当前栈中最高的频率是多少。
2、我们得知道一个频率 freq
对应的元素有哪些,且这些元素要有时间顺序。
3、随着 pop
的调用,每个 val
对应的频率会变化,所以还得维持一个映射记录每个 val
对应的 freq
。
设计实现
综上,我们可以先实现 FreqStack
所需的数据结构:
1 | type FreqStack struct { |
我们来亲自构建stack
这一数据结构及其方法。
1 | type stack struct { // 栈可以用一个简单的切片来表示 |
其实这有点类似前文LFU算法,注意 freqToVal
中 val
列表用一个栈实现,如果一个 freq
对应的元素有多个,根据栈的特点,可以首先取出最近添加的元素。
要记住在 push
和 pop
方法中同时修改 maxFreq
、VF
表、FV
表,否则容易出现 bug。
Push
方法
现在,我们可以来实现 push
方法了。
我们要分别实现对FreqStack
结构体中三个元素的更新。
valToFreq(VF表)
:如果val
对应的映射存在,则映射到的值加1;如果不存在,则初始为1;freqToVal(FV表)
:如果新加入的val
对应的新的freq
在FV
表中没有初始化的栈,则创建一个新栈,将该val
入栈;否则直接入栈;maxFreq
:比较新的freq
与原始的maxFreq
,取大者作为maxFreq
。
1 | func (this *FreqStack) Push(val int) { |
Pop()
方法
我们要分别实现对FreqStack
结构体中三个元素的更新。
freqToVal(FV表)
:找到maxFreq
在FV
表中的映射,如果映射到的stack
容量为1(说明只有一个数的频率是maxFreq
),则将maxFreq
减一并将栈顶元素出栈;否则直接将栈顶元素出栈;valToFreq(VF表)
:找到出栈元素对应的VF
表的映射(代表其出现频率),将其直接减一;maxFreq
:已经在修改FV
表时进行了选择性的修改,不做特殊操作。
1 | func (this *FreqStack) Pop() int { |
总结
完整的最大栈实现代码如下:
1 | type stack struct { |
- Post title:最大栈
- Post author:洪笳淏
- Create time:2021-10-03 15:16:00
- Post link:https://jiahaohong1997.github.io/2021/10/03/最大栈/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.
Comments