在问 · 算法题解

622. 设计循环队列

中等设计定长数组 + 取模力扣原题 ↗

题目描述

设计一个容量固定的循环队列类 MyCircularQueue。它遵循先进先出,存储空间首尾相接,出队后空出的位置可以被后续入队的元素再次使用。不允许使用语言自带的队列库。

MyCircularQueue(k):创建一个最多容纳 k 个元素的空队列。enQueue(value):把 value 放到队尾,成功返回 true,队列已满时返回 false。deQueue():移除队首元素,成功返回 true,队列为空时返回 false。

Front():返回队首元素,队列为空时返回 -1。Rear():返回队尾元素,队列为空时返回 -1。isEmpty():队列为空时返回 true。isFull():队列已满时返回 true。

测试数据以两个数组给出:第一个是依次调用的方法名,第二个是对应的参数;输出数组给出每次调用的返回值,构造函数对应 null。

示例 1
输入:操作 = ["MyCircularQueue","enQueue","enQueue","enQueue","enQueue","Rear","isFull","deQueue","enQueue","Rear"]
参数 = [[3],[1],[2],[3],[4],[],[],[],[4],[]]
输出:[null,true,true,true,false,3,true,true,true,4]

解释:容量为 3,第 4 次入队因队满返回 false;出队一次后再放入 4 成功,此时队尾为 4。

数据范围

  • 所有元素值在 0 到 1000 之间。
  • 操作次数在 1 到 1000 之间。
  • 不要使用内置的队列实现。

解题思路:定长数组 + 取模

用长度为 k 的数组加两个变量:head 是队首下标,size 是元素个数。队尾的下一个空位是 (head + size) % k,队尾元素是 (head + size - 1) % k。入队写入空位并 size+1;出队只需 head 后移一位(取模)并 size-1,旧值不必清理。

为什么正确

队列中的元素依次位于下标 head, head+1, …, head+size-1(均对 k 取模),且 0 ≤ size ≤ k。

复杂度分析

所有操作 O(1);空间 O(k)。

易错点

只用 head 和 tail 两个指针时,head == tail 既可能是空也可能是满,需要多开一格或记录 size;这里用 size 来区分。Rear 的下标要减 1 后再取模,不要忘记绕回。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class MyCircularQueue:
    def __init__(self, k: int = 3):
        self.q = [0] * k
        self.head = 0
        self.size = 0
        self.cap = k

    def enQueue(self, value: int) -> bool:
        if self.size == self.cap:
            return False
        self.q[(self.head + self.size) % self.cap] = value
        self.size += 1
        return True

    def deQueue(self) -> bool:
        if self.size == 0:
            return False
        self.head = (self.head + 1) % self.cap
        self.size -= 1
        return True

    def Front(self) -> int:
        if self.size == 0:
            return -1
        return self.q[self.head]

    def Rear(self) -> int:
        if self.size == 0:
            return -1
        return self.q[(self.head + self.size - 1) % self.cap]

    def isEmpty(self) -> bool:
        return self.size == 0

    def isFull(self) -> bool:
        return self.size == self.cap

载入编辑器,自己跑一遍 →

其他解法

数组实现靠取模让下标在固定空间里循环,内存连续;链表实现按需创建节点,只靠 size 控制容量。各操作都是 O(1)。

解法 2:单链表 时间 O(1),空间 O(k)

用单链表保存队列元素,维护头指针 head、尾指针 tail 和当前元素个数 size。入队时先检查 size 是否已达容量,再在 tail 后接上新节点。出队时把 head 后移一位。队首和队尾分别读 head 和 tail。

不需要取模,也不用预先分配整块数组。代价是每次入队都要新建节点,并且每个元素多一个指针的开销。

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


class MyCircularQueue:
    def __init__(self, k: int = 3):
        self.cap = k
        self.size = 0
        self.head = None
        self.tail = None

    def enQueue(self, value: int) -> bool:
        if self.size == self.cap:
            return False
        node = ListNode(value)
        if self.size == 0:
            self.head = self.tail = node
        else:
            self.tail.next = node
            self.tail = node
        self.size += 1
        return True

    def deQueue(self) -> bool:
        if self.size == 0:
            return False
        self.head = self.head.next
        self.size -= 1
        return True

    def Front(self) -> int:
        return -1 if self.size == 0 else self.head.val

    def Rear(self) -> int:
        return -1 if self.size == 0 else self.tail.val

    def isEmpty(self) -> bool:
        return self.size == 0

    def isFull(self) -> bool:
        return self.size == self.cap

设计 专题的其他题目

查看 设计 全部题目 →