【每日一题Day42】最大频率栈 | 哈希表+大顶堆 哈希表+栈

简介: 思路:在本题中,每次需要优先弹出频率最大的元素,如果频率最大元素有多个,则优先弹出靠近栈顶的元素。因此,我们可以考虑将栈序列分解为多个频率不同的栈序列,每个栈维护同一频率的元素。当元素入栈时频率增加,将元素加入到更高频率的栈中,低频率栈中的元素不需要出栈。当元素出栈时,将频率最高的栈的栈顶元素出栈即可。

最大频率栈【LC895】


Design a stack-like data structure to push elements to the stack and pop the most frequent element from the stack.


Implement the FreqStack class:


  • FreqStack() constructs an empty frequency stack.
  • void push(int val) pushes an integer val onto the top of the stack.
  • int pop()removes and returns the most frequent element in the stack.


。If there is a tie for the most frequent element, the element closest to the stack’s top is removed and returned.


解封啦 但是真的好冷 不愿出门


哈希表+大顶堆


  • 思路:


按照题意,每次弹出使用频率最高的元素,如果使用频率相等,那么弹出最近放入栈中的元素。题目中的使用频率指放入最大频率栈的次数,不包括弹出的次数。


因此,我们可以使用HashMap记录每个元素的使用频率;并构造节点Node,将新节点的元素值、使用频率和到达时间记录其中;使用大顶堆存储节点,每次弹出顶部节点即可,弹出后需要更新使用频率。


  • 实现:


。使用valueToCount存储每个元素及其对应的使用频率即次数

。构造节点node存储val值,以及其对应的使用频率和到达时间

。使用优先队列存放节点,优先队列以节点的使用频率从大到小、到达时间从大到小的顺序排序【大顶堆】:


  • 每次添加一个元素都构造一个新节点,存放该数值的使用频率以及到达时间
  • 每次删除一个元素都将优先队列使用频率最高到达时间最近的节点删除,并将map集合中的次数-1


  • 代码


class FreqStack {
    Map<Integer,Integer> valueToCount;
    PriorityQueue<Node> queue;
    int time;
    public FreqStack() {
        valueToCount = new HashMap<>();
        queue = new PriorityQueue<>(new Comparator<Node>() {
            @Override
            public int compare(Node node1, Node node2) {
                if (node2.count == node1.count){
                    return node2.time - node1.time;
                }
                return node2.count - node1.count;
            }
        });
    }
    public void push(int val) {
        int count = valueToCount.getOrDefault(val,0) + 1;
        valueToCount.put(val, count);
        Node node = new Node(val,count,++time);
        queue.add(node);               
    }
    public int pop() {
        Node delNode = queue.poll();
        int val = delNode.val;
        valueToCount.put(val,valueToCount.get(val) - 1);
        return val;
    }
}
class Node{
    int val;
    int count;
    int time;
    public Node(int val, int count, int time){
        this.val = val;
        this.count = count;
        this.time = time;
    }
    // public int compareTo(Object o) {
    //     ListNode o1 = (ListNode)o;
    //     return o1.count - this.count;
    // }
}
/**
 * Your FreqStack object will be instantiated and called as such:
 * FreqStack obj = new FreqStack();
 * obj.push(val);
 * int param_2 = obj.pop();
 */


。复杂度


  • 时间复杂度:O ( l o g n ),构建优先队列需要O ( l o g n ) 的时间复杂度,push和pop方法均需要O ( l o g n ) 的时间复杂度


  • 空间复杂度:O ( n )


哈希表+多个栈


  • 思路:在本题中,每次需要优先弹出频率最大的元素,如果频率最大元素有多个,则优先弹出靠近栈顶的元素。因此,我们可以考虑将栈序列分解为多个频率不同的栈序列,每个栈维护同一频率的元素。当元素入栈时频率增加,将元素加入到更高频率的栈中,低频率栈中的元素不需要出栈。当元素出栈时,将频率最高的栈的栈顶元素出栈即可。


  • 实现


。使用HashMap<Integer,Integer>存储每个元素及其对应的使用频率

。使用maxFreq记录当前的最大使用频率

。使用HashMap<Integer,Deque<Integer>>存储每个频率对应的元素值


  • push:将该元素压入对应的频率栈中
  • pop:将最高频率的栈的栈顶元素出栈


  • 代码


class FreqStack {
    private Map<Integer, Integer> freq;
    private Map<Integer, Deque<Integer>> group;
    private int maxFreq;
    public FreqStack() {
        freq = new HashMap<Integer, Integer>();
        group = new HashMap<Integer, Deque<Integer>>();
        maxFreq = 0;
    }
    public void push(int val) {
        freq.put(val, freq.getOrDefault(val, 0) + 1);
        group.putIfAbsent(freq.get(val), new ArrayDeque<Integer>());
        group.get(freq.get(val)).push(val);
        maxFreq = Math.max(maxFreq, freq.get(val));
    }
    public int pop() {
        int val = group.get(maxFreq).peek();
        freq.put(val, freq.get(val) - 1);
        group.get(maxFreq).pop();
        if (group.get(maxFreq).isEmpty()) {
            maxFreq--;
        }
        return val;
    }
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/maximum-frequency-stack/solutions/1997251/zui-da-pin-lu-zhan-by-leetcode-solution-moay/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


.复杂度


  • 时间复杂度:O ( 1 ),构建优先队列需要O(logn)的时间复杂度,push和pop方法均需要O(1)的时间复杂度


  • 空间复杂度:O ( n )
目录
相关文章
|
22天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
109 9
|
19天前
|
存储 算法 Java
散列表的数据结构以及对象在JVM堆中的存储过程
本文介绍了散列表的基本概念及其在JVM中的应用,详细讲解了散列表的结构、对象存储过程、Hashtable的扩容机制及与HashMap的区别。通过实例和图解,帮助读者理解散列表的工作原理和优化策略。
29 1
散列表的数据结构以及对象在JVM堆中的存储过程
|
13天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
21 1
|
16天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
21天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
60 16
|
19天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
21天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
47 4
|
1月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
33 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
25天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
初步认识栈和队列
初步认识栈和队列
61 10