最大频率栈
字数 1890 2025-12-21 23:58:11
最大频率栈
题目描述
设计一个基于哈希的栈,称为“频率栈”,它支持两种操作:
push(int val):将整数val推入栈中。pop():弹出并返回栈中出现频率最高的元素。如果频率最高的元素不止一个,则返回最接近栈顶的那个元素。
你需要实现 FreqStack 类:
FreqStack()初始化一个空的频率栈。void push(int val)将一个元素val推入栈中。int pop()弹出并返回频率最高的元素(规则如上)。
示例
输入:
["FreqStack", "push", "push", "push", "push", "push", "push", "pop", "pop", "pop", "pop"]
[[], [5], [7], [5], [7], [4], [5], [], [], [], []]
输出:
[null, null, null, null, null, null, null, 5, 7, 5, 4]
解释:
FreqStack freqStack = new FreqStack();
freqStack.push(5); // 栈为 [5]
freqStack.push(7); // 栈为 [5,7]
freqStack.push(5); // 栈为 [5,7,5]
freqStack.push(7); // 栈为 [5,7,5,7]
freqStack.push(4); // 栈为 [5,7,5,7,4]
freqStack.push(5); // 栈为 [5,7,5,7,4,5]
freqStack.pop(); // 返回 5,因为 5 出现频率最高(3次)。栈变成 [5,7,5,7,4]。
freqStack.pop(); // 返回 7,因为 5 和 7 频率都是2,但 7 最接近栈顶。栈变成 [5,7,5,4]。
freqStack.pop(); // 返回 5,栈变成 [5,7,4]。
freqStack.pop(); // 返回 4,栈变成 [5,7]。
解题过程循序渐进讲解
1. 理解问题核心
我们需要一个数据结构,能快速回答“当前哪个元素频率最高?如果并列,哪个最近被推入?”。
- 频率最高:需要追踪每个值的出现次数。
- 最近推入:需要记录同一频率的所有值,且按推入顺序排列(栈的特性,后进先出)。
2. 选择数据结构
- 哈希表
freq:键是元素值val,值是该元素到当前为止的出现次数。 - 哈希表
group:键是频率freq,值是一个栈,保存所有达到这个频率的元素(按推入顺序)。
例如,当某个元素第一次出现时,频率为1,它进入group[1]的栈;当它第二次出现,频率变为2,它又进入group[2]的栈。 - 变量
maxFreq:记录当前全局最大频率,用于快速定位group中该弹出哪个栈。
3. 操作步骤
push(val) 操作:
- 更新该元素的频率:
freq[val] += 1,得到新的频率f。 - 更新全局最大频率:
maxFreq = max(maxFreq, f)。 - 将
val推入group[f]对应的栈中。
注意:同一个val会在多个频率的栈中出现(比如频率1、2、3的栈中都有它),这保证了当它被弹出后,下一层频率的栈中还有它。
pop() 操作:
- 从
group[maxFreq]的栈顶弹出元素x(这就是当前频率最高且最近推入的元素)。 - 更新该元素的频率:
freq[x] -= 1。 - 如果
group[maxFreq]的栈为空,说明当前最大频率已无元素,将maxFreq -= 1。 - 返回
x。
4. 举例推演
以题目示例为例,初始状态:
freq = {}, group = {}, maxFreq = 0。
-
push(5):freq[5] = 1,maxFreq = 1group[1] = [5]
-
push(7):freq[7] = 1,maxFreq = 1group[1] = [5, 7]
-
push(5):freq[5] = 2,maxFreq = 2group[2] = [5]
-
push(7):freq[7] = 2,maxFreq = 2group[2] = [5, 7]
-
push(4):freq[4] = 1,maxFreq = 2group[1] = [5, 7, 4]
-
push(5):freq[5] = 3,maxFreq = 3group[3] = [5]
-
pop():- 从
group[3]弹出5,group[3]变空。 freq[5] = 2,maxFreq降为2。- 返回
5。
- 从
-
pop():- 从
group[2]弹出7(栈顶是7)。 freq[7] = 1,group[2]变为[5](不空,maxFreq仍为2)。- 返回
7。
- 从
-
pop():- 从
group[2]弹出5,group[2]变空。 freq[5] = 1,maxFreq降为1。- 返回
5。
- 从
-
pop():- 从
group[1]弹出4(栈顶是4)。 freq[4] = 0,group[1]变为[5, 7](不空)。- 返回
4。
- 从
5. 时间复杂度与空间复杂度
push和pop都是 O(1) 时间操作(哈希表与栈操作均为常数时间)。- 空间复杂度:O(n),n 为推入元素的总次数(每个元素会在多个频率栈中出现一次)。
6. 关键点总结
- 核心思想是“将相同频率的元素用栈组织”,这样自然满足“同频率时取最近推入”的条件。
maxFreq的维护保证了能快速找到最高频率对应的栈。- 同一个元素存在于多个频率栈中,模拟了它在不同频率级别的“存在状态”,使得弹出后能正确降级到下一频率。