LeetCode 232简单栈 / 队列设计
用栈实现队列 图解题解
这道题到底在问什么
只用两个栈(仅能 push 顶 / pop 顶 / 看顶),实现队列的 push(队尾入)、pop(队首出)、peek(看队首)。
- 输入
- push 1,2 → peek → pop → push 3 → pop
- 输出
- 1, 1, 2
最优解:一步一步想明白
- 3记住这句,下面每一帧都在演它。
- 4初始:in、out 都空。
- 5push(1):新元素一律压 in 栈。in=[1],out=[]。
- 6push(2):新元素一律压 in 栈。in=[1,2],out=[]。
- 7out 空,先倒栈。看 in 怎么翻进 out。
- 8倒栈:in 顶 2 弹出压入 out(顺序翻转)。in=[1],out=[2]。
- 9倒栈:in 顶 1 弹出压入 out(顺序翻转)。in=[],out=[2,1]。
- 10peek 返回 1:翻转后队首浮到 out 顶,只读不弹。out=[2,1]。
- 11pop 返回 1:out 非空就直接弹顶,无需倒栈。out=[2],in=[]。
- 12push(3):新元素一律压 in 栈。in=[3],out=[2]。
- 13pop 返回 2:out 非空就直接弹顶,无需倒栈。out=[],in=[3]。
- 14批量入队后,出队时一次倒栈把它们全翻过去。
- 15push(4):新元素一律压 in 栈。in=[3,4],out=[]。
- 16push(5):新元素一律压 in 栈。in=[3,4,5],out=[]。
- 17倒栈:in 顶 5 弹出压入 out(顺序翻转)。in=[3,4],out=[5]。
- 18倒栈:in 顶 4 弹出压入 out(顺序翻转)。in=[3],out=[5,4]。
- 19倒栈:in 顶 3 弹出压入 out(顺序翻转)。in=[],out=[5,4,3]。
- 20peek 返回 3:翻转后队首浮到 out 顶,只读不弹。out=[5,4,3]。
- 21pop 返回 3:out 非空就直接弹顶,无需倒栈。out=[5,4],in=[]。
- 22pop 返回 4:out 非空就直接弹顶,无需倒栈。out=[5],in=[]。
- 23push(6):新元素一律压 in 栈。in=[6],out=[5]。
- 24push(7):新元素一律压 in 栈。in=[6,7],out=[5]。
- 25pop 返回 5:out 非空就直接弹顶,无需倒栈。out=[],in=[6,7]。
- 26倒栈:in 顶 7 弹出压入 out(顺序翻转)。in=[6],out=[7]。
- 27倒栈:in 顶 6 弹出压入 out(顺序翻转)。in=[],out=[7,6]。
- 28pop 返回 6:out 非空就直接弹顶,无需倒栈。out=[7],in=[]。
- 29pop 返回 7:out 非空就直接弹顶,无需倒栈。out=[],in=[]。
- 30验证:先进先出顺序 1..7 全部正确。两栈清空。
⚠️ 容易写错的地方
✗ 错:每次出队都倒栈
✓ 对:只在 out 空时倒
out 非空时顶就是队首,倒了反而打乱顺序
✗ 错:倒一半就停
✓ 对:倒栈要把 in 全部倒空
留半截会让后续顺序错乱
✗ 错:peek 把元素弹掉
✓ 对:peek 只读 out 顶不弹
弹了下次 pop 就丢了队首
完整代码(Python / C++ / Java)
Python
class MyQueue:
def __init__(self):
self.inS, self.outS = [], []
def push(self, x):
self.inS.append(x) # 入队压 in 栈
def _move(self):
if not self.outS: # out 空才倒栈
while self.inS:
self.outS.append(self.inS.pop())
def pop(self):
self._move(); return self.outS.pop()
def peek(self):
self._move(); return self.outS[-1]
def empty(self):
return not self.inS and not self.outSC++
class MyQueue {
stack<int> inS, outS;
void move(){
if(outS.empty()) // out 空才倒栈
while(!inS.empty()){ outS.push(inS.top()); inS.pop(); }
}
public:
void push(int x){ inS.push(x); } // 入队压 in 栈
int pop(){ move(); int v=outS.top(); outS.pop(); return v; }
int peek(){ move(); return outS.top(); }
bool empty(){ return inS.empty() && outS.empty(); }
};Java
class MyQueue {
private Deque<Integer> inS = new ArrayDeque<>();
private Deque<Integer> outS = new ArrayDeque<>();
public void push(int x) { inS.push(x); } // 入队压 in 栈
private void move() {
if (outS.isEmpty()) // out 空才倒栈
while (!inS.isEmpty()) outS.push(inS.pop());
}
public int pop() { move(); return outS.pop(); }
public int peek() { move(); return outS.peek(); }
public boolean empty() { return inS.isEmpty() && outS.isEmpty(); }
}复杂度
时间
均摊 O(1)
每个元素一生只被倒一次(in→out)
空间
O(n)
两个栈共存 n 个元素
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 用栈实现队列 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么均摊是 O(1)?+
每个元素最多被压入/弹出各栈一次:进 in 一次、倒进 out 一次、出 out 一次,共常数次操作,均摊到每个元素 O(1)。
反过来用栈实现栈中栈/用队列实现栈呢?+
用队列实现栈(LC225):每次 push 后把前面的元素轮转到队尾,使新元素到队首,让 pop 拿到最后压入的。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 用栈实现队列 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。