[Leetcode学习-c++&java]Maximum Frequency Stack(最大频次栈)

46 篇文章 0 订阅

问题:

难度:hard

说明:

要求设计一个统计频次的栈,push() 往栈内存放元素,pop() 返回栈内频次最多的元素,并移除该元素,如果频次一样,就返回最靠近栈顶的一个。

题目连接:https://leetcode.com/problems/maximum-frequency-stack/submissions/

输入范围:

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

输入案例:

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:
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].

我的代码:

思路上跟 LRU 差不多的,频次优先,栈顶优先,只是少了插入优先,其实可用优先队列来做 PriorityQueue 。

1、使用 stack 存放 每次插入的元素。

2、使用 cache 记录每个元素值出现的 频次。

3、使用 优先队列,存放优先的频次值。

4、使用 优先队列  HashMap indexs,记录每个频次对应的优先 stack 索引。

具体是这样的指针指向(图后面补上):

 

但是可以更加简单化:

1、因为每次存放进来的时候,stack 索引只增不减,所以 indexs 不必使用优先队列,可以改为 普通 ArrayList 即可。

2、如果改下存放思路:

使用 cache 记录每个元素出现频次。

然后使用频次 - 数值组 来存放数值: List<List<Integer>>,那么 根据 频次 来分组,每个组内都存放一个 数值的 list,再来一个 maxFre 记录最大的频次,每次获取组都获取maxFre 的对应组,并且获取组最后一个元素,那么这个元素就是最大的并且最靠近栈顶的频次数值。

Java:

class FreqStack {
    int maxFre = 0; // 用于记录频次, 降低创建 ArrayList 次数
    Map<Integer, Integer> cache; // 暂存频率节点
    private static List<List<Integer>> freValsStack = new ArrayList<>();; // 暂存 频次 - 数据组

    public FreqStack() {
        cache = new HashMap<>();
    }

    public void push(int x) {
        Integer fre = cache.getOrDefault(x, 0) + 1;
        if(fre > freValsStack.size()) {
            freValsStack.add(new ArrayList<>());
        }
        freValsStack.get(fre - 1).add(x); // 每个频次组最后一个元素必定是最新插入的
        cache.put(x, fre);
        maxFre = Math.max(maxFre, fre);
    }

    public int pop() {
        if(freValsStack.isEmpty()) return -1;
        // 移除频次最多
        List<Integer> topList = freValsStack.get(maxFre - 1);
        Integer res = topList.remove(topList.size() - 1);
        // 频次 - 1
        if(topList.isEmpty()) maxFre --;
        cache.put(res, cache.get(res) - 1);
        return res;
    }
}

C++(后面补上):

 

使用优先队列的 Java:

    class FreqStack {
        int top;
        List<Integer> stack; // 暂存数据
        Map<Integer, Integer> cache; // 暂存频率节点
        PriorityQueue<Integer> queue; // 频率优先
        Map<Integer, Queue<Integer>> indexs; // 索引优先

        public FreqStack2() {
            queue = new PriorityQueue<>((i1, i2) -> i2 - i1);
            indexs = new HashMap<>();
            cache = new HashMap<>();
            stack = new ArrayList<>();
        }

        public void push(int x) {
            stack.add(x);
            Integer fre;
            // 获取该数值频率
            fre = cache.getOrDefault(x, 0) + 1;
            cache.put(x, fre);

            if(indexs.containsKey(fre)) { // 增加该频率优先索引
                Queue<Integer> q = indexs.get(fre);
                q.offer(top ++);
            } else {
                Queue<Integer> q = new PriorityQueue<>((t1, t2) -> t2 - t1);
                q.offer(top ++);
                indexs.put(fre, q);
            }
            // 添加优先频率
            queue.offer(fre);
        }

        public int pop() {
            if(queue.isEmpty()) return -1;
            Integer fre = queue.poll();
            Integer index = indexs.get(fre).poll();
            Integer res = stack.get(index);
            cache.put(res, cache.get(res) - 1);
            return res;
        }
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值