LeetCode 716. Max Stack - 链表(Linked List)系列题27

本题要求设计一个Max Stack,除了支持常规的堆栈操作外,还需能快速获取和移除最大元素。通过在双向链表基础上结合SortedDict,可以实现在O(logn)时间复杂度内完成相关操作,满足题目的要求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Design a max stack data structure that supports the stack operations and supports finding the stack's maximum element.

Implement the MaxStack class:

  • MaxStack() Initializes the stack object.
  • void push(int x) Pushes element x onto the stack.
  • int pop() Removes the element on top of the stack and returns it.
  • int top() Gets the element on the top of the stack without removing it.
  • int peekMax() Retrieves the maximum element in the stack without removing it.
  • int popMax() Retrieves the maximum element in the stack and removes it. If there is more than one maximum element, only remove the top-most one.

Example 1:

Input
["MaxStack", "push", "push", "push", "top", "popMax", "top", "peekMax", "pop", "top"]
[[], [5], [1], [5], [], [], [], [], [], []]
Output
[null, null, null, null, 5, 5, 1, 5, 1, 5]

Explanation
MaxStack stk = new MaxStack();
stk.push(5);   // [5] the top of the stack and the maximum number is 5.
stk.push(1);   // [5, 1] the top of the stack is 1, but the maximum is 5.
stk.push(5);   // [5, 1, 5] the top of the stack is 5, which is also the maximum, because it is the top most one.
stk.top();     // return 5, [5, 1, 5] the stack did not change.
stk.popMax();  // return 5, [5, 1] the stack is changed now, and the top is different from the max.
stk.top();     // return 1, [5, 1] the stack did not change.
stk.peekMax(); // return 5, [5, 1] the stack did not change.
stk.pop();     // return 1, [5] the top of the stack and the max element is now 5.
stk.top();     // return 5, [5] the stack did not change.

Constraints:

  • -107 <= x <= 107
  • At most 104 calls will be made to pushpoptoppeekMax, and popMax.
  • There will be at least one element in the stack when poptoppeekMax, or popMax is called.

Follow up: Could you come up with a solution that supports O(1) for each top call and O(logn) for each other call? 

题目要求设计一个堆栈除了支持一般堆栈具有的接口函数:push(), pop(), top(),还需要支持返回堆栈中的最大值:peekMax(),和弹出堆栈中的最大值:popMax()。

本题可以在系统自带的堆栈的基础上实现题目所要求的堆栈。如果不用系统自带的而是让我自己实现一个堆栈的话,通常我们会用双向链表来实现,因为双向链表的插入和删除操作的时间复杂度可以达到在O(1)。

如果是一个普通的堆栈那么用一个双向链表就足够了,因为只要在链表头做插入和删除操作就足够了。但是还要支持peekMax()和popMax()的话,那就要求我们能够迅速找到链表中具有最大值的那个节点,遍历链表来寻找的时间复杂度是O(n)无法满足题目要求,因此可以借助于一个有序的字典SortedDict来实现快速查找,用SortedDict来存储键-值(key-values)的最大特点就是字典里的所有键是有序的,详细使用可以参考用Python刷LeetCode必备知识点2 - SortedDict

对于本题,用SortedDict存储的键(keys)-值(values)分别是节点值和节点指针。由于keys是有序的那就可以快速获得最大值也就是键列表中的最后那一个SortedDict.keys()[-1],于是就可以得到具有最大值的节点指针,如果是删除操作就可以在链表中把对应的节点删除。SortedDict的插入操作时间复杂度是O(logn),满足题目要求。

from sortedcontainers import SortedDict

class ListNode:
    
    def __init__(self, val = None, prev = None, next = None):
        self.val = val
        self.next = next
        self.prev = prev
        
class MaxStack:

    def __init__(self):
        self.head = ListNode(-1)
        self.tail = ListNode(-1)
        self.head.next = self.tail
        self.tail.prev = self.head
        self.v2n = SortedDict()

    def push(self, x: int) -> None:
        node = ListNode(x, self.head, self.head.next)
        self.head.next.prev = node
        self.head.next = node
        if x not in self.v2n:
            self.v2n[x] = [node]
        else:
            self.v2n[x].append(node)
        
    def pop(self) -> int:
        node = self.head.next
        self.head.next = node.next
        node.next.prev = self.head
        self.v2n[node.val].pop()
        if not self.v2n[node.val]:
            self.v2n.pop(node.val)
        return node.val

    def top(self) -> int:
        return self.head.next.val

    def peekMax(self) -> int:
        val= self.v2n.keys()[-1]
        return val

    def popMax(self) -> int:
        val = self.v2n.keys()[-1]
        node = self.v2n[val].pop()
        if not self.v2n[val]:
            self.v2n.pop(val)        
        node.next.prev = node.prev
        node.prev.next = node.next
        
        return node.val

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值