题目描述
思路解析动画文字版
记住三样东西:front(队头格)、rear(队尾格)、size(元素个数)。下标越界就取模绕回,这就是「循环」的全部秘密。
刚建好的双端队列:底盘是长度 5 的数组,全是空位 ·。还没有任何元素,size=0。
下一步:insertLast(1)。先看当前状态——队列里是 [空],size=0。准备从队尾插入 1。
insertLast(1):队列原本是空的,把第一个元素放进下标 0,front 和 rear 都指这里,size 变 1。
下一步:insertLast(2)。先看当前状态——队列里是 [1],size=1。准备从队尾插入 2。
insertLast(2):从队尾进。rear 往右挪一格到下标 1,把 2 写进去,size 变 2。
下一步:insertLast(3)。先看当前状态——队列里是 [1 , 2],size=2。准备从队尾插入 3。
insertLast(3):从队尾进。rear 往右挪一格到下标 2,把 3 写进去,size 变 3。
下一步:insertFront(9)。先看当前状态——队列里是 [1 , 2 , 3],size=3。准备从队头插入 9。
insertFront(9):从队头进。front 往左挪一格,越过左边界,取模绕回到末尾下标 4,写入 9,size 变 4。
下一步:insertFront(8)。先看当前状态——队列里是 [9 , 1 , 2 , 3],size=4。准备从队头插入 8。
insertFront(8):从队头进。front 往左挪一格到下标 3,写入 8,size 变 5。
现在 size=5 等于容量,队列满了。isFull() 返回 true——这时候再 insert 会直接失败,不能覆盖已有元素。
下一步:deleteLast()。先看当前状态——队列里是 [8 , 9 , 1 , 2 , 3],size=5。准备删除队尾元素。
deleteLast():从队尾出。把队尾那格(标红,原值 3)清空,rear 往左收一格回到下标 1。size 变 4。
下一步:insertFront(7)。先看当前状态——队列里是 [8 , 9 , 1 , 2],size=4。准备从队头插入 7。
insertFront(7):从队头进。front 往左挪一格到下标 2,写入 7,size 变 5。
现在 size=5 等于容量,队列满了。isFull() 返回 true——这时候再 insert 会直接失败,不能覆盖已有元素。
下一步:deleteFront()。先看当前状态——队列里是 [7 , 8 , 9 , 1 , 2],size=5。准备删除队头元素。
deleteFront():从队头出。把队头那格(标红,原值 7)清空,front 往右收一格到下标 3。size 变 4。
下一步:deleteFront()。先看当前状态——队列里是 [8 , 9 , 1 , 2],size=4。准备删除队头元素。
deleteFront():从队头出。把队头那格(标红,原值 8)清空,front 往右收一格到下标 4。size 变 3。
回看整趟:数组长度始终是 5,元素没真的搬家,动的只是 front、rear、size 三个变量。下标越界就取模绕回——这就是循环双端队列。
三个高频追问:两个下标的含义、为什么要 size、以及 k=0 边界。
参考代码
class MyCircularDeque: def __init__(self, k): self.cap = k self.q = [0]*k # 定长数组 self.front = self.rear = 0 self.size = 0 def insertFront(self, v): if self.size == self.cap: return False if self.size: self.front = (self.front-1) % self.cap self.q[self.front] = v; self.size += 1; return True def insertLast(self, v): if self.size == self.cap: return False if self.size: self.rear = (self.rear+1) % self.cap self.q[self.rear] = v; self.size += 1; return True def deleteFront(self): if not self.size: return False self.size -= 1 if self.size: self.front = (self.front+1) % self.cap return True def deleteLast(self): if not self.size: return False self.size -= 1 if self.size: self.rear = (self.rear-1) % self.cap return True def getFront(self): return -1 if not self.size else self.q[self.front] def getRear(self): return -1 if not self.size else self.q[self.rear] def isEmpty(self): return self.size == 0 def isFull(self): return self.size == self.cap复杂度
- 时间:O(1),每个操作只是改几个下标、读写一格,跟容量无关
- 空间:O(k),一个长度为 k 的定长数组,外加 front/rear/size 三个变量
易错点
面试追问把动画讲成自己的话
追问front 和 rear 分别指什么?
追问为什么要单独存一个 size,不能只靠 front 和 rear 判断空/满吗?
追问如果容量 k 传 0 会怎样?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
LFU 缓存
LeetCode 460 · 困难 · 沿着 设计套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题