LeetCodeCampsDay10

使用队列实现栈;

使用栈实现队列;

以及两个关于栈的题目

232. 用栈实现队列

https://leetcode.cn/problems/implement-queue-using-stacks/

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]

解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

提示:

  • 1 <= x <= 9
  • 最多调用 100pushpoppeekempty
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

进阶:

  • 你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。

思路

  1. 维护两个列表list,其中一个用于入栈(stack_in),一个出栈(stack_out)
  2. push函数,直接入栈到stack_in
  3. empty函数,只要stack_out或stack_in不为空即可
  4. pop函数,先判断是否为“empyt”;
    1. 其次,如果stack_out中有数字,就出栈这个数;
    2. stack_out为空的时候,将stack_in全部转移到stack_out,再弹出一个数(比如下面动画弹出“1”和“3”时,明显是将stack_in的所有数据都移到了stack_out中)

下面动画模拟以下队列的执行过程:

执行语句:
queue.push(1);
queue.push(2);
queue.pop(); 注意此时的输出栈的操作 ,输出1
queue.push(3);
queue.push(4);
queue.pop(); # 输出2
queue.pop();注意此时的输出栈的操作 输出3
queue.pop(); # 输出4
queue.empty();

img

代码

  • 时间复杂度O(1)
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
class MyQueue:

def __init__(self):
self.stack_in = []
self.stack_out = []

def push(self, x: int) -> None:
self.stack_in.append(x)

def pop(self) -> int:
if self.empty():
return None
# 如果stack_out中有数据,直接从stack_out中弹出这个
if self.stack_out:
return self.stack_out.pop()
else:
# 先将stack_in的全部转移到stack_out中
for i in range(len(self.stack_in)):
self.stack_out.append(self.stack_in.pop())
# 再从stack_out中弹出一个
return self.stack_out.pop()


def peek(self) -> int:
ans = self.pop()
self.stack_out.append(ans)
return ans

def empty(self) -> bool:
return not (self.stack_in or self.stack_out)


# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()

225. 用队列实现栈

https://leetcode.cn/problems/implement-stack-using-queues/

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppopempty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false

注意:

  • 你只能使用队列的标准操作 —— 也就是 push to backpeek/pop from frontsizeis empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]

解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

提示:

  • 1 <= x <= 9
  • 最多调用100pushpoptopempty
  • 每次调用 poptop 都保证栈不为空

**进阶:**你能否仅用一个队列来实现栈。

思路

  1. 使用两个队列实现栈,一个输入队列que_in,一个输出队列que_backup
  2. push函数,直接用que_in加入;
  3. empty函数,如果queue_in不为空即可
  4. pop函数,先判断是否为空;
    1. 先将L-1个数字转移到que_backup,再将que_backup与que_in交换,再将最后一个数字弹出
  5. top函数,调用pop函数,再将数据添加回que_in即可

模拟的队列执行语句如下:

1
2
3
4
5
6
7
8
9
queue.push(1);        
queue.push(2);
queue.pop(); // 注意弹出的操作
queue.push(3);
queue.push(4);
queue.pop(); // 注意弹出的操作
queue.pop();
queue.pop();
queue.empty();

img

代码

  • 时间复杂度O(1)
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
class MyStack:
from collections import deque
def __init__(self):
self.queue_in = deque()
self.queue_out = deque()

def push(self, x: int) -> None:
self.queue_in.append(x)

def pop(self) -> int:
if self.empty():
return None

# 由于queue是FIFO,比如stack中有[1->3->4 如果想弹出4,
# 此时队列A中 4->3->1,需要将3->1这两个数字转移到另一个队列B,再将4弹出去
# 这里是len(self.queue_in) - 1
for i in range(len(self.queue_in) - 1):
self.queue_out.append(self.queue_in.popleft())
# 然后进行两个队列的交换,因为只有一个数据在queue_in中,其余都在queue_out
self.queue_in, self.queue_out = self.queue_out, self.queue_in
return self.queue_out.popleft()

def top(self) -> int:
# 调用self.pop,将pop出来的数字再加回到self.queue_in里
ans = self.pop()
self.queue_in.append(ans)
return ans

def empty(self) -> bool:
return not self.queue_in


# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()

思路二(仅用一个队列)

  1. 上述使用的que_backup可以省略掉,将数据反复加入到queue_in即可了

代码

  • 时间复杂度O(1)
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
class MyStack:
from collections import deque
def __init__(self):
self.queue_in = deque()


def push(self, x: int) -> None:
self.queue_in.append(x)

def pop(self) -> int:
if self.empty():
return None

# 由于queue是FIFO,比如stack中有[1->3->4 如果想弹出4,
# 此时队列A中 4->3->1,需要将3->1这两个数字转移到另一个队列B,再将4弹出去
# 这里是len(self.queue_in) - 1
for i in range(len(self.queue_in) - 1):
# 重新添加回去
self.queue_in.append(self.queue_in.popleft())
return self.queue_in.popleft()

def top(self) -> int:
# 调用self.pop,将pop出来的数字再加回到self.queue_in里
ans = self.pop()
self.queue_in.append(ans)
return ans

def empty(self) -> bool:
return not self.queue_in


# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()

20. 有效的括号

https://leetcode.cn/problems/valid-parentheses/

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

**输入:**s = “()”

**输出:**true

示例 2:

**输入:**s = “()[]{}”

**输出:**true

示例 3:

**输入:**s = “(]”

**输出:**false

示例 4:

**输入:**s = “([])”

**输出:**true

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成

思路

  1. 使用栈解决
    1. 如果是左括号就入栈
    2. 如果是右括号就出栈(且栈不空)并判断是否是对应的左括号(使用下标判断)
    3. 否则就直接返回False,比如s=’]’
  2. 最后再判断栈是否还有剩余,比如s=’[’

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def isValid(self, s: str) -> bool:
# 如果是左括号就入栈,如果是右括号就出栈
leftList = ['(', '{', '[']
rightList = [')', '}', ']']

stack = []

for i in s:
if i in leftList:
stack.append(i)
elif i in rightList and len(stack) != 0:
l = stack.pop()
if leftList.index(l) != rightList.index(i):
return False
else:
return False
if len(stack) != 0:
return False
return True

1047. 删除字符串中的所有相邻重复项

https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/

给出由小写字母组成的字符串 s重复项删除操作会选择两个相邻且相同的字母,并删除它们。

s 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:

1
2
3
4
输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

提示:

  1. 1 <= s.length <= 105
  2. s 仅由小写英文字母组成

思路

  1. 使用栈可以解决,用栈的top函数,可惜python的列表只有pop没有top;不过可以将弹出的重新添加回去
  2. 如果栈不空,就弹出最后元素并与s[i]判断
    1. 如果相等就不执行操作了(因为已经弹出了)
    2. 如果不相等,则需要将弹出的元素添加回去,并且再将s[i]入栈
  3. 如果栈为空,默认添加s[i]入栈

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
def removeDuplicates(self, s: str) -> str:
# 使用栈的top(),可惜python的列表只有pop没有top
#
stack = list()
for i in s:
# 如果栈不空,就弹出并判断
if len(stack):
# 默认弹出来并进行判断
l = stack.pop()
if l != i:
# 如果l不等于i,再添加回去
stack.append(l)
stack.append(i)
# 栈空就默认添加
else:
stack.append(i)
return "".join(stack)