最大栈
最大栈介绍
直接参考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