1670. 设计前中后队列

目录

设计一个支持前、中、后三个位置插入和删除的队列 — FrontMiddleBack 队列实现详解

题目描述

中间位置的定义

解题分析

解题方法

方案:使用两个双端队列(deque)

操作实现细节:

维护平衡的关键函数 _rebalance():

代码实现(Python)

复杂度分析

示例说明

其他实现思路与对比

总结


设计一个支持前、中、后三个位置插入和删除的队列 — FrontMiddleBack 队列实现详解

题目描述

设计一个特殊的队列数据结构,支持在队列的 前、中、后 三个位置进行元素的插入和删除操作。具体要求如下:

实现一个类 FrontMiddleBack,包含以下方法:

  • FrontMiddleBack():初始化队列。
  • void pushFront(int val):将元素 val 添加到队列最前面。
  • void pushMiddle(int val):将元素 val 添加到队列的正中间。
  • void pushBack(int val):将元素 val 添加到队列最后面。
  • int popFront():删除并返回队列最前面的元素,如果队列为空则返回 -1
  • int popMiddle():删除并返回队列中间的元素,如果队列为空则返回 -1。如果有两个中间元素,则删除靠前面的那个。
  • int popBack():删除并返回队列最后面的元素,如果队列为空则返回 -1

中间位置的定义

  • 若队列长度为奇数,中间位置就是正中间的那个元素。
  • 若队列长度为偶数,中间位置有两个元素,此时中间位置指的是靠前的那个元素。

例如:

  • 队列 [1, 2, 3, 4, 5],中间位置是元素 3
  • 队列 [1, 2, 3, 4, 5, 6],中间位置是元素 3(靠前那个)。

示例:

  • [1, 2, 3, 4, 5] 中间插入 6,结果为 [1, 2, 6, 3, 4, 5]
  • [1, 2, 3, 4, 5, 6] 弹出中间元素,弹出 3,结果为 [1, 2, 4, 5, 6]

解题分析

实现一个支持三处插入和删除的队列,关键在于:

  • 插入和删除中间元素 的效率问题。如果使用普通列表或数组,每次中间插入或删除都可能导致 O(n) 的移动开销,效率较低。
  • 如何快速定位中间元素,以及在保持中间位置定义的同时,维持队列元素的顺序。

要实现所有操作的高效性(理想情况是均摊 O(1) 或接近 O(1)),我们需要采用更巧妙的数据结构。


解题方法

方案:使用两个双端队列(deque

思路是将整个队列拆分成两个部分:

  • 左半部分left):存储队列前半部分元素
  • 右半部分right):存储队列后半部分元素

我们确保:

  • left 的元素个数 ≥ right 的元素个数,且两者长度差不超过 1。
  • 这样,队列的“中间”元素就始终是 left 的最后一个元素。

操作实现细节:

  • pushFront(val)
    • val 插入到 left 队列头部。
    • 之后重新平衡两个队列,保证长度条件。
  • pushMiddle(val)
    • 如果 leftright 长,将 left 的末尾元素移动到 right 的头部。
    • val 添加到 left 的末尾。
    • 这样保证新元素插入在靠前的中间位置。
  • pushBack(val)
    • val 添加到 right 的末尾。
    • 重新平衡。
  • popFront()
    • 如果两个队列都为空,返回 -1。
    • 优先从 left 的头部弹出元素;如果 left 空,从 right 头部弹出。
    • 重新平衡。
  • popMiddle()
    • 如果队列为空,返回 -1。
    • 弹出 left 的末尾元素。
    • 重新平衡。
  • popBack()
    • 如果队列为空,返回 -1。
    • 优先从 right 末尾弹出;如果 right 为空,从 left 末尾弹出。
    • 重新平衡。

维护平衡的关键函数 _rebalance()

  • 如果 leftright 长超过 1 个元素,将 left 的末尾元素移动到 right 的头部。
  • 如果 rightleft 长,将 right 的头部元素移动到 left 的末尾。

这样保证了:

  • left 始终保持元素数量 ≥ right
  • 差值不超过 1

代码实现(Python)

from collections import deque

class FrontMiddleBackQueue:
    def __init__(self):
        self.left = deque()
        self.right = deque()

    def _rebalance(self):
        # 保证left的大小 >= right,且差值不超过1
        while len(self.left) > len(self.right) + 1:
            self.right.appendleft(self.left.pop())
        while len(self.left) < len(self.right):
            self.left.append(self.right.popleft())

    def pushFront(self, val: int) -> None:
        self.left.appendleft(val)
        self._rebalance()

    def pushMiddle(self, val: int) -> None:
        if len(self.left) > len(self.right):
            self.right.appendleft(self.left.pop())
        self.left.append(val)

    def pushBack(self, val: int) -> None:
        self.right.append(val)
        self._rebalance()

    def popFront(self) -> int:
        if not self.left and not self.right:
            return -1
        val = self.left.popleft() if self.left else self.right.popleft()
        self._rebalance()
        return val

    def popMiddle(self) -> int:
        if not self.left and not self.right:
            return -1
        val = self.left.pop()
        self._rebalance()
        return val

    def popBack(self) -> int:
        if not self.left and not self.right:
            return -1
        val = self.right.pop() if self.right else self.left.pop()
        self._rebalance()
        return val

复杂度分析

  • 时间复杂度
    • 所有操作的均摊时间复杂度均为 O(1)

由于 _rebalance() 最多每次移动一个元素,且 dequeappend/pop/appendleft/popleft 都是 O(1),所以操作高效。

  • 空间复杂度
    • 使用两个 deque,总空间是元素数目的两倍,空间复杂度为 O(n)

示例说明

q = FrontMiddleBackQueue()

q.pushFront(1)      # [1]
q.pushBack(2)       # [1, 2]
q.pushMiddle(3)     # [1, 3, 2]
q.pushMiddle(4)     # [1, 4, 3, 2]
print(q.popFront()) # 返回 1,队列变成 [4, 3, 2]
print(q.popMiddle())# 返回 4,队列变成 [3, 2]
print(q.popBack())  # 返回 2,队列变成 [3]
print(q.popFront()) # 返回 3,队列变成 []
print(q.popFront()) # 返回 -1,队列为空

通过以上示例,可以看到:

  • pushMiddle 在两个中间元素时,插入靠前的位置。
  • popMiddle 删除靠前的中间元素。
  • 其他操作正常维护顺序。

其他实现思路与对比

  • 单链表或数组实现
    • 直接插入或删除中间元素需要移动大量元素,导致操作 O(n)。
  • 平衡树或跳表
    • 可实现 O(log n) 插入和删除,但实现复杂度较高。
  • 两个双端队列(本方案):
    • 实现简单且操作效率高,适合此题。

总结

通过巧妙使用两个双端队列,并在每次操作后保持平衡,我们成功实现了一个支持在 前、中、后 三个位置插入和删除元素的队列结构,且保证了所有操作的高效执行。

这个设计既优雅又实用,是数据结构设计中的经典案例,值得学习和掌握。


如果你对该题目实现还有其他疑问或想用其他语言版本实现,欢迎随时告诉我!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值