返回

LeetCode 1670 设计前中后队列:膀胱局归来,用队列演绎队列的艺术!

前端

前中后队列:膀胱局归来!

欢迎来到 LeetCode 1670 题的精彩世界!在这个题目中,您将面临一项有趣而富有挑战性的任务:设计一个队列,同时支持在前、中、后三个位置进行 push 和 pop 操作。想象一下,您正在参加一场膀胱局,而这个队列将模拟您在膀胱局中的位置。

就像膀胱局一样,我们的队列也分为三个区域:前区、中区和后区。当您进入膀胱局时,您需要先排队,也就是进入队列的前区。然后,随着时间的推移,您会逐渐向后移动,直到到达中区和后区。同样地,在我们的队列中,您也可以从前区、中区和后区进行 push 和 pop 操作。

膀胱局中的艺术

为了更好地理解这个算法,让我们将它与膀胱局联系起来。当您进入膀胱局时,您首先需要在门口排队,这就是前区。在前区,您需要等待一段时间,直到有人离开膀胱局,您才能进入中区。一旦进入中区,您就可以自由地选择一个位置坐下,直到您需要去卫生间。这时,您就可以从后区离开膀胱局了。

在这个膀胱局的类比中,我们能够清晰地看到队列是如何工作的。前区是队列的开头,中区是队列的中间部分,后区是队列的结尾。当您执行 push 操作时,您就是在把某人添加到队列的前区或中区。当您执行 pop 操作时,您就是在把某人从队列的后区移走。

算法实现:从膀胱局到代码世界

现在,让我们从膀胱局的类比中跳脱出来,回到代码世界,看看如何实现这个算法。在我们的代码中,我们将使用两个双向链表来模拟队列的前区和后区。然后,我们将在中区使用一个指针来跟踪队列的中间位置。这样,我们就可以在 O(1) 的时间复杂度内完成 push 和 pop 操作。

class FrontMiddleBackQueue:

    def __init__(self):
        self.front = DoublyLinkedList()
        self.middle = None
        self.back = DoublyLinkedList()

    def pushFront(self, val: int) -> None:
        self.front.addFirst(val)
        self.updateMiddle()

    def pushMiddle(self, val: int) -> None:
        if self.middle is None:
            self.front.addFirst(val)
            self.middle = self.front.head
        else:
            self.front.addAfter(val, self.middle)
            self.middle = self.middle.next

    def pushBack(self, val: int) -> None:
        self.back.addLast(val)
        self.updateMiddle()

    def popFront(self) -> int:
        if self.front.isEmpty():
            return -1
        val = self.front.removeFirst()
        self.updateMiddle()
        return val

    def popMiddle(self) -> int:
        if self.middle is None:
            return -1
        val = self.middle.val
        self.middle = self.middle.next if self.middle.next else self.middle.prev
        self.updateMiddle()
        return val

    def popBack(self) -> int:
        if self.back.isEmpty():
            return -1
        val = self.back.removeLast()