原文链接: https://leetcode-cn.com/problems/maximum-frequency-stack
英文原文
Design a stack-like data structure to push elements to the stack and pop the most frequent element from the stack.
Implement the FreqStack
class:
FreqStack()
constructs an empty frequency stack.void push(int val)
pushes an integerval
onto the top of the stack.int pop()
removes and returns the most frequent element in the stack.- If there is a tie for the most frequent element, the element closest to the stack's top is removed and returned.
Example 1:
Input ["FreqStack", "push", "push", "push", "push", "push", "push", "pop", "pop", "pop", "pop"] [[], [5], [7], [5], [7], [4], [5], [], [], [], []] Output [null, null, null, null, null, null, null, 5, 7, 5, 4] Explanation FreqStack freqStack = new FreqStack(); freqStack.push(5); // The stack is [5] freqStack.push(7); // The stack is [5,7] freqStack.push(5); // The stack is [5,7,5] freqStack.push(7); // The stack is [5,7,5,7] freqStack.push(4); // The stack is [5,7,5,7,4] freqStack.push(5); // The stack is [5,7,5,7,4,5] freqStack.pop(); // return 5, as 5 is the most frequent. The stack becomes [5,7,5,7,4]. freqStack.pop(); // return 7, as 5 and 7 is the most frequent, but 7 is closest to the top. The stack becomes [5,7,5,4]. freqStack.pop(); // return 5, as 5 is the most frequent. The stack becomes [5,7,4]. freqStack.pop(); // return 4, as 4, 5 and 7 is the most frequent, but 4 is closest to the top. The stack becomes [5,7].
Constraints:
0 <= val <= 109
- At most
2 * 104
calls will be made topush
andpop
. - It is guaranteed that there will be at least one element in the stack before calling
pop
.
中文题目
实现 FreqStack
,模拟类似栈的数据结构的操作的一个类。
FreqStack
有两个函数:
push(int x)
,将整数x
推入栈中。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] 解释: 执行六次 .push 操作后,栈自底向上为 [5,7,5,7,4,5]。然后: pop() -> 返回 5,因为 5 是出现频率最高的。 栈变成 [5,7,5,7,4]。 pop() -> 返回 7,因为 5 和 7 都是频率最高的,但 7 最接近栈顶。 栈变成 [5,7,5,4]。 pop() -> 返回 5 。 栈变成 [5,7,4]。 pop() -> 返回 4 。 栈变成 [5,7]。
提示:
- 对
FreqStack.push(int x)
的调用中0 <= x <= 10^9
。 - 如果栈的元素数目为零,则保证不会调用
FreqStack.pop()
。 - 单个测试样例中,对
FreqStack.push
的总调用次数不会超过10000
。 - 单个测试样例中,对
FreqStack.pop
的总调用次数不会超过10000
。 - 所有测试样例中,对
FreqStack.push
和FreqStack.pop
的总调用次数不会超过150000
。
通过代码
官方题解
方法:栈
思路
显然,我们更关心元素的频率。令 freq
作为 $x$ 到 $x$ 的出现次数的映射 Map
。
此外,我们也(可能)关心 maxfreq
,即栈中任意元素的当前最大频率。这是理所应当的事情,因为我们必须弹出频率最高的元素。
那么当前主要的问题就变成了:在具有相同的(最大)频率的元素中,怎么判断那个元素是最新的?我们可以使用栈来查询这一信息:靠近栈顶的元素总是相对更新一些。
为此,我们令 group
作为从频率到具有该频率的元素的映射。到目前,我们已经实现了 FreqStack
的所有必要的组件。
算法
实际上,作为实现层面上的一点细节,如果 x
的频率为 f
,那么我们将获取在所有 group[i] (i <= f)
中的 x
,而不仅仅是栈顶的那个。这是因为每个 group[i]
都会存储与第 i
个 x
副本相关的信息。
此后,我们仅仅需要如上所述维护 freq
,group
,以及 maxfreq
。
class FreqStack {
Map<Integer, Integer> freq;
Map<Integer, Stack<Integer>> group;
int maxfreq;
public FreqStack() {
freq = new HashMap();
group = new HashMap();
maxfreq = 0;
}
public void push(int x) {
int f = freq.getOrDefault(x, 0) + 1;
freq.put(x, f);
if (f > maxfreq)
maxfreq = f;
group.computeIfAbsent(f, z-> new Stack()).push(x);
}
public int pop() {
int x = group.get(maxfreq).pop();
freq.put(x, freq.get(x) - 1);
if (group.get(maxfreq).size() == 0)
maxfreq--;
return x;
}
}
class FreqStack(object):
def __init__(self):
self.freq = collections.Counter()
self.group = collections.defaultdict(list)
self.maxfreq = 0
def push(self, x):
f = self.freq[x] + 1
self.freq[x] = f
if f > self.maxfreq:
self.maxfreq = f
self.group[f].append(x)
def pop(self):
x = self.group[self.maxfreq].pop()
self.freq[x] -= 1
if not self.group[self.maxfreq]:
self.maxfreq -= 1
return x
复杂度分析
时间复杂度:对于
push
和pop
操作,$O(1)$。空间复杂度:$O(N)$,其中
N
为FreqStack
中元素的数目。
统计信息
通过次数 | 提交次数 | AC比率 |
---|---|---|
7894 | 14241 | 55.4% |
提交历史
提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
---|