剑指offer 面试题09. 用两个栈实现队列(易)
栈和队列有何特点?如何通过画图,将抽象问题形式化?
栈和队列有何特点?
栈:先进后出;队列:先进先出。
如何通过画图,将抽象问题形象化?
参考题解的两幅图片
Tag
栈和队列
题目
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
1
2
3
4
5
6
7
8
9
10
11
12class CQueue:
def __init__(self):
def appendTail(self, value: int) -> None:
def deleteHead(self) -> int:
# Your CQueue object will be instantiated and called as such:
# obj = CQueue()
# obj.appendTail(value)
# param_2 = obj.deleteHead()1
2
3
4输入:
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
输出:[null,null,3,-1]1
2
3
4
5
6
7
8
9
10
11
12
13
14输入:
["CQueue","appendTail","deleteHead","deleteHead"]
这一行表示每一行代码的操作
[[],[3],[],[]]
这个表示每一行代码操作后对应的结果
举例:
CQueue 表示新建一个CQueue对象,对应的结果为[]。
appendTail 表示执行一个appendTail()操作,对应要被操作的元素为3
deleteHead 表示执行一个deleteHead操作,对应的结果为[]
deleteHead 表示执行一个deleteHead操作,对应的结果为[]
以上的输入其实是一个代码执行的步骤描述与其对应结果或操作。
并不是说,上面的“输入”表示的输入程序验证的数据。
1 |
|
提示: 1 <= values <= 10000 最多会对 appendTail、deleteHead 进行 10000 次调用。
直觉
设置两个栈 Stack1
和 Stack2
输入数据,即调用 appendTail
的时候都填充到 Stack1
中(a、b、c),要 deleteHead
的时候,就依次从 Stack1
中弹出再填充到 Stack2
中 (c、b、a),当全部填充到 Stack2
中之后,直接弹出 Stack2
中的栈顶元素(也就是之前最早入队的元素)即可。
算法 - 只要是入队,都是往stack1里面压栈。 - 出队时,先尝试将stack1中的数据转移到stack2中。 - 经过转移之后,如果stack2中还是没有任何一行数据,说明stack1也是空的,整体为空栈,返回\(-1\)。 - 如果不是空队,直接返回stack2栈顶的元素,也就是之前最早入队的元素即可。

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77import unittest
from typing import List
class CQueue:
def __init__(self):
self.stack1 = list()
self.stack2 = list()
def appendTail(self, value: int) -> None:
# 只要是入队,都是往stack1里面压栈。
self.stack1.append(value)
def deleteHead(self) -> int:
# 出队时,先尝试将stack1中的数据转移到stack2中
if len(self.stack2) <= 0:
while len(self.stack1) > 0:
self.stack2.append(self.stack1.pop())
# 经过转移之后,如果stack2中还是没有任何一行数据,说明stack1里面也是空的,这就是一个空队
if len(self.stack2) == 0:
return -1
# 如果不是空队,直接返回stack2栈顶的元素,就是之前最早入队的元素即可。
return self.stack2.pop()
class TestCQueue(unittest.TestCase):
def setUp(self):
self.test_class = CQueue()
self.test_class2 = CQueue()
# 测试样例1
# 输入:
# ["CQueue","appendTail","deleteHead","deleteHead"]
# [[],[3],[],[]]
# 输出:[null,null,3,-1]
def test_CQueue_1(self):
res = [None] # CQueue = []
res.append(self.test_class.appendTail(3)) # [None, None] CQueue = [3]
res.append(self.test_class.deleteHead()) # [None, None, 3] CQueue = []
res.append(self.test_class.deleteHead()) # [None, None, 3, -1] CQueue = []
answer = [None, None, 3, -1]
self.assertEqual(res, answer)
# 测试样例2
# 输入:
# ["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
# [[],[],[5],[2],[],[]]
# 输出:[null,-1,null,null,5,2]
def test_CQueue_2(self):
res = [None] # CQueue = []
res.append(self.test_class2.deleteHead()) # [None, -1] CQueue = []
res.append(self.test_class2.appendTail(5)) # [None, -1, None] CQueue = [5]
res.append(self.test_class2.appendTail(2)) # [None, -1, None, None] CQueue = [5, 2]
res.append(self.test_class2.deleteHead()) # [None, -1, None, None, 5] CQueue = []
res.append(self.test_class2.deleteHead()) # [None, -1, None, None, 5, 2] CQueue = []
answer = [None, -1, None, None, 5, 2]
self.assertEqual(res, answer)
def tearDown(self):
del self.test_class
del self.test_class2
if __name__ == '__main__':
# 允许添加多个测试的方法
# 1、构造用例集
suite = unittest.TestSuite()
# 2、允许添加多个测试,执行顺序是按加载顺序进行。
suite.addTest(TestCQueue("test_CQueue_1"))
suite.addTest(TestCQueue("test_CQueue_2"))
# 3、实例化runner类
runner = unittest.TextTestRunner()
# 4、执行测试
runner.run(suite)
举一反三:用两个队列实现一个栈
直觉
算法
- 还是使用两个队列
Queue1
和Queue2
。 - 只要是入栈,只往
Queue1
里面入队。 - 出栈时,先判断
Queue2
是不是空的。- 当
Queue2
不为空时,说明已经弹栈过了,依次从Queue2
中出队再入队到Queue1
中,当Queue2
还剩一个元素时,不再出队了,将其返回。 - 当
Queue2
为空且Queue1
不为空时,依次从Queue1
中出队再入队到Queue2
中,当Queue1
还剩一个元素时,不再填充了,将其返回。 - 当
Queue2
和Queue1
同时为空时,说明是空栈,返回 \(-1\)。
- 当

代码
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!