实现 FreqStack,模拟类似栈的数据结构的操作的一个类。FreqStack 有两个函数:
输入:
["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。
我们需要关心两个因素:元素距离栈顶的位置、元素频次
比较直观的做法是用排序做,pq 按照上述两个字段进行排序,
class FreqStack {
Queue<int[]> q; // a[0]值;a[1]频率;a[2]离栈顶位置
Map<Integer, Integer> m;
int top;
public FreqStack() {
q = new PriorityQueue<>((e1, e2) -> {
if (e1[1] == e2[1])
return e2[2]-e1[2];
return e2[1]-e1[1];
});
m = new HashMap<>();
top = 0;
}
public void push(int x) {
int c = m.getOrDefault(x, 0)+1;
q.add(new int[]{x, c, top++});
m.put(x, c);
}
public int pop() {
int[] a = q.poll();
m.put(a[0], m.get(a[0])-1);
return a[0];
}
}
复杂度分析
更优的 O ( n ) O(n) O(n) 的做法是利用一个 map,:
class FreqStack {
public:
unordered_map<int, int> cnt;
unordered_map<int, stack<int>> m;
int maxc;
FreqStack() {
}
void push(int x) {
int c = ++cnt[x];
if (c > maxc) maxc = c;
m[c].push(x);
}
int pop() {
int v = m[maxc].top(); m[maxc].pop(); cnt[v]--;
if (m[maxc].size() == 0) maxc--;
return v;
}
};
复杂度分析