题目

Implement FreqStack, a class which simulates the operation of a stack-like data structure.

FreqStack has two functions:

  • push(int x), which pushes an integer x onto the stack.
  • pop(), which removes and returns the most frequent element in the stack.
    • If there is a tie for most frequent element, the element closest to the top of the stack is removed and returned.

Example 1:

  1. Input:
  2. ["FreqStack","push","push","push","push","push","push","pop","pop","pop","pop"],
  3. [[],[5],[7],[5],[7],[4],[5],[],[],[],[]]
  4. Output: [null,null,null,null,null,null,null,5,7,5,4]
  5. Explanation:
  6. After making six .push operations, the stack is [5,7,5,7,4,5] from bottom to top. Then:
  7. pop() -> returns 5, as 5 is the most frequent.
  8. The stack becomes [5,7,5,7,4].
  9. pop() -> returns 7, as 5 and 7 is the most frequent, but 7 is closest to the top.
  10. The stack becomes [5,7,5,4].
  11. pop() -> returns 5.
  12. The stack becomes [5,7,4].
  13. pop() -> returns 4.
  14. The stack becomes [5,7].

Note:

  • Calls to FreqStack.push(int x) will be such that 0 <= x <= 10^9.
  • It is guaranteed that FreqStack.pop() won’t be called if the stack has zero elements.
  • The total number of FreqStack.push calls will not exceed 10000 in a single test case.
  • The total number of FreqStack.pop calls will not exceed 10000 in a single test case.
  • The total number of FreqStack.push and FreqStack.pop calls will not exceed 150000 across all test cases.

题意

实现一个类似栈的数据结构的两种操作:

  1. push,将一个新值加入到结构中
  2. pop,返回结构中出现频率最大的数,如果有两个这样的数,则返回后加入的那个数

思路

个人做法是维护一个优先队列pq,将其内部的排序规则指定为题目中的规则。每次push先从pq中删去对应的结点(如果存在),更新后再将结点重新加入pq中;每次pop则从pq头部取结点,处理后返回值。

官方的方法是维护两个HashMap,一个映射 数x->出现频率,一个映射 出现频率->出现对应频率的数组成的栈(后加入的更靠近栈顶)。


代码实现

Java

HashMap+PriorityQueue

  1. class FreqStack {
  2. private Queue<Item> pq;
  3. private Map<Integer, Item> map;
  4. private int cnt = -1;
  5. public FreqStack() {
  6. pq = new PriorityQueue<Item>((a, b) -> {
  7. if (a.freq == b.freq) {
  8. return b.stack.peek() - a.stack.peek();
  9. } else {
  10. return b.freq - a.freq;
  11. }
  12. });
  13. map = new HashMap<>();
  14. }
  15. public void push(int x) {
  16. map.putIfAbsent(x, new Item(x));
  17. Item item = map.get(x);
  18. pq.remove(item);
  19. item.freq += 1;
  20. item.stack.push(++cnt);
  21. pq.offer(item);
  22. }
  23. public int pop() {
  24. Item item = pq.poll();
  25. item.freq -= 1;
  26. item.stack.pop();
  27. if (item.freq != 0) {
  28. pq.offer(item);
  29. }
  30. return item.val;
  31. }
  32. class Item {
  33. int val = 0;
  34. int freq = 0;
  35. Deque<Integer> stack = new ArrayDeque<>();
  36. Item(int x) {
  37. val = x;
  38. }
  39. }
  40. }

HashMap+Stack

  1. class FreqStack {
  2. private Map<Integer, Integer> freq;
  3. private Map<Integer, Deque<Integer>> group;
  4. private int maxFreq;
  5. public FreqStack() {
  6. freq = new HashMap<>();
  7. group = new HashMap<>();
  8. }
  9. public void push(int x) {
  10. int newFreq = freq.getOrDefault(x, 0) + 1;
  11. maxFreq = Math.max(maxFreq, newFreq);
  12. freq.put(x, newFreq);
  13. group.putIfAbsent(newFreq, new ArrayDeque<>());
  14. group.get(newFreq).push(x);
  15. }
  16. public int pop() {
  17. int x = group.get(maxFreq).pop();
  18. freq.put(x, freq.get(x) - 1);
  19. if (group.get(maxFreq).isEmpty()) maxFreq--;
  20. return x;
  21. }
  22. }