895. 最大频率栈

问题描述

  1. 最大频率栈 实现 FreqStack,模拟类似栈的数据结构的操作的一个类。

FreqStack 有两个函数:

push(int x),将整数 x 推入栈中。 pop(),它移除并返回栈中出现最频繁的元素。
如果最频繁的元素不只一个,则移除并返回最接近栈顶的元素。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-frequency-stack

解题思路

这题依然主要是按照频率和按照时间排序,和之前写的LFU 算法c++的两种实现 问题上是类似的。只不过 LFU中,每个元素最多出现一次。
因此,依旧按照类似的思路,提供两种解法。

思路一【hash表+优先级队列】

  • 第一种是将频率信息和时间戳信息记录到每一个元素节点里面,然后再按照频率从大到小、时间从大到小的顺序排序,每次都取前一个。
  • 这里依然需要一个hash表来记录<值,频率>的映射,因为push的时候或者pop的时候都需要知道该元素是否在优先级中队列中出现过,以及它的出现的频率。因为新出现的频率总是它原来的频率+1。
  • 这个和LFU算法不同,LFU算法中,get函数是带参数的,必须返回想要get(x)的那个x,因此仅仅记录频率还不够,还得知道它在哪,然后在优先级队列中进行更新频率和时间(删除再新建节点插入,优先级队列只能删除堆顶元素,因此LFU中使用set实现)。而本题中,pop返回的是堆顶元素,并且直接删除即可。push的时候是创建新节点,根本不需要管旧节点在什么地方。
struct Node{
    int val;
    int time;
    int freq;
    Node(){}
    Node(int _val, int _time, int _freq){
        val=_val;
        time=_time;
        freq=_freq;
    }

    
};
struct cmp{
    bool operator () (const Node& lhs,const Node&rhs)const {
        // 默认大根堆,因此我们按频率从小到大、时间戳从小到大排序即可
        return lhs.freq==rhs.freq?lhs.time<rhs.time:lhs.freq<rhs.freq;
    }
};
class FreqStack {
public:
    
    unordered_map<int,int> v2f;

    priority_queue<Node,vector<Node>,cmp>pq;
    int global_time=0;

    FreqStack() {
    }
    
    void push(int val) {
        int f;
        if(v2f.count(val)){
            // 如果已经有了,则新节点的频率+1
            f = ++v2f[val];
        }else{
            f=1;
            v2f[val]=1;
        }
        Node n(val,global_time++,f);
        pq.push(n);
    }
    
    int pop() {
        if(pq.empty()){
            return -1;
        }
        Node n=pq.top();
        pq.pop();
        // 更新hash表
        v2f[n.val]--;
        if(!v2f[n.val])
        {
            v2f.erase(n.val);
        }
        return n.val;
    }
};

思路二:hash表+单链表

  • 使用数组下标来实现freq的有序,数组下标就是freq(默认freq=0,这样不浪费)
  • 数组中的每个元素是一个单链表(也可以就直接是栈),每次从链表头插入,删除也是从直接删头。
  • 使用hash表记录<val,freq>的映射
  • push:hash表更新freq,生成新节点,放到对应freq的链表头部。
  • pop:从数组最后一个链表头部删除,如果链表空了则把这个数组元素也删除
class FreqStack {
public:
    vector<list<int>> array;
    unordered_map<int,int>v2f;

    FreqStack() {
        array.push_back(list<int>());
    }
    
    void push(int val) {
        int f;
        if(v2f.count(val)){
            f = ++v2f[val];
            
        }else{
            f =0;
            v2f[val]=0;
        }
        if(f==array.size()){
            array.push_back(list<int>());
        }
        array[f].push_front(val);
    }
    
    int pop() {
        int res = array.back().front();
        
        v2f[res]--;
        if(v2f[res]==-1){
            v2f.erase(res);
        }
        array.back().pop_front();
        if(array.back().empty())
        array.pop_back();
        return res;
        
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值