Implement FreqStack
, a class which simulates the operation of a stack-like data structure.html
FreqStack
has two functions:git
push(int x)
, which pushes an integer x
onto the stack.pop()
, which removes and returns the most frequent element in the stack.
Example 1:github
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: After making six .push operations, the stack is [5,7,5,7,4,5] from bottom to top. Then: pop() -> returns 5, as 5 is the most frequent. The stack becomes [5,7,5,7,4]. pop() -> returns 7, as 5 and 7 is the most frequent, but 7 is closest to the top. The stack becomes [5,7,5,4]. pop() -> returns 5. The stack becomes [5,7,4]. pop() -> returns 4. The stack becomes [5,7].
Note:数组
FreqStack.push(int x)
will be such that 0 <= x <= 10^9
.FreqStack.pop()
won't be called if the stack has zero elements.FreqStack.push
calls will not exceed 10000
in a single test case.FreqStack.pop
calls will not exceed 10000
in a single test case.FreqStack.push
and FreqStack.pop
calls will not exceed 150000
across all test cases.
这道题让咱们实现一种最大频率栈,有入栈和出栈功能,须要每次出栈的都是栈中出现频率最大的数字,如有多个数字的频率相同,那么离栈顶最近的元素先出栈。刚开始看到这道题的时候,博主立马联想到了 LRU Cache 和 LFU Cache,想着会不会也须要在迭代器上作文章,但实际是我想多了,虽然同为 Hard 的题目,这道题的解法却要比以前那两道要简单的多。这里只跟数字出现的频率有关,只有在频率相等的状况下才会考虑栈的后入先出的特性,因此必定是须要统计栈中每一个数字出现的频率的,咱们使用一个 HashMap 来创建每一个数字跟其出现次数之间的映射。因为频率相等的数字可能有多个,因此咱们必须知道某个特性频率下都有哪些数字,再用一个 HashMap 来创建频率和该频率下全部的数字之间的映射,能够将这些数组放到一个数组或者一个栈中,这里为了简便起见,就使用一个数组了。另外,咱们还须要维护一个当前最大频率的变量,能够经过这个值到 HashMap 中快速定位数组的位置。好,一切准备就绪以后就开始解题吧,对于入栈函数 push(),首先须要将x对应的映射值加1,并更新最大频率 mxFreq,而后就是要把x加入当前频率对应的数组中,注意若某个数字出现了3次,那么数字会分别加入频率为 1,2,3 的映射数组中。接下来看出栈函数 pop() 如何实现,因为咱们知道当前最大频率 mxFreq,就能够直接去 HashMap 中取出该频率下的全部数字的数组,题目说了若频率相等,取离栈顶最近的元素,这里就是数组末尾的数组,取到以后,要将该数字从数组末尾移除。移除以后,咱们要检测一下,若数组此时为空了,说明当前最大频率下以后一个数字,取出以后,最大频率就要自减1,还有不要忘记的就是取出数字的自身的频率值也要自减1,参见代码以下:函数
解法一:code
class FreqStack { public: FreqStack() {} void push(int x) { mxFreq = max(mxFreq, ++freq[x]); m[freq[x]].push_back(x); } int pop() { int x = m[mxFreq].back(); m[mxFreq].pop_back(); if (m[freq[x]--].empty()) --mxFreq; return x; } private: int mxFreq; unordered_map<int, int> freq; unordered_map<int, vector<int>> m; };
咱们还可使用 multimap 来创建频率和数字之间的映射,利用其可重复的特性,那么同一个频率就能够映射多个数字了。同时,因为 multimap 默认是按从小到大排序的,而咱们但愿按频率从大到小排序,因此加上一个参数使其改变排序方式。在入栈函数中,将x的频率自增1,而后跟x组成 pair 对儿加入 multimap 中。在出栈函数中,因为其是按从大到小排序的,并且后进的排在前面,那么第一个映射对儿就是频率最大且最后加入的数字,将其取出并从 multimap 中移除,并同时将该数字的映射频率值减1便可,参见代码以下:htm
解法二:blog
class FreqStack { public: FreqStack() {} void push(int x) { m.insert({++freq[x], x}); } int pop() { int x = m.begin()->second; m.erase(m.begin()); --freq[x]; return x; } private: unordered_map<int, int> freq; multimap<int, int, greater_equal<int>> m; };
Github 同步地址:排序
https://github.com/grandyang/leetcode/issues/895element
参考资料:
https://leetcode.com/problems/maximum-frequency-stack/
https://leetcode.com/problems/maximum-frequency-stack/discuss/163410/C%2B%2BJavaPython-O(1)