任務
232. 用棧實現佇列
請你僅使用兩個棧實現先入先出佇列。佇列應當支援一般佇列支援的所有操作(push、pop、peek、empty)
思路
算是一個模擬類的題目,用py中,用列表加上限制條件表示棧(只能用pop表示對棧頂元素出棧處理)
- push:用stackIn儲存入隊元素
- pop: 出隊時,分三種情況,
- 如果佇列為空,則返回None
- 如果stackOut中還有元素,則彈出棧頂元素
- 如果stackOut中沒有元素,則將stackIn中的元素依次彈出並加入到stackOut棧中,全部完成後,彈出stackOut棧頂元素
- peek: 彈出stackOut棧頂元素並儲存其值,然後重新加入棧頂,返回之前儲存的值
- empty: 只有stackOut和stackIn全為空,才為空
class MyQueue:
def __init__(self):
self.stackIn = []
self.stackOut = []
def push(self, x: int) -> None:
self.stackIn.append(x)
def pop(self) -> int:
if self.empty(): return None
if self.stackOut: return self.stackOut.pop()
else:
while self.stackIn:
self.stackOut.append(self.stackIn.pop())
return self.stackOut.pop()
def peek(self) -> int:
res = self.pop()
self.stackOut.append(res)
return res
def empty(self) -> bool:
return (not self.stackIn and not self.stackOut)
# 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. 用佇列實現棧
請你僅使用兩個佇列實現一個後入先出(LIFO)的棧,並支援普通棧的全部四種操作(push、top、pop 和 empty)
思路
兩個佇列的思路類似上一題,實際只需要一個佇列即可。此外,由於用py實現,如果用List模擬佇列,移除時需要pop(1),時間複雜度為O(n),因此用deque和popleft代替來模擬佇列。
思路時出棧時,實際就是將佇列的前n-1個元素放到隊尾,再彈出佇列首元素即可。而top更簡單棧頂元素即為隊尾元素。
class MyStack:
def __init__(self):
self.queue = deque()
def push(self, x: int) -> None:
self.queue.append(x)
def pop(self) -> int:
if self.empty():return None
for i in range(len(self.queue)-1):
self.queue.append(self.queue.popleft())
return self.queue.popleft()
#這種方法雖然能實現,由於是雙端佇列,訪問末尾時間複雜度上也不會有問題,但是若當作普通佇列模擬,則可採用top2的方法
#實際py中沒必要,實現是為了其他語言且題意要求用普通佇列的情況下
def top(self) -> int:
if self.empty():return None
return self.queue[-1]
def top2(self)->int:
res = self.pop()
self.queue.append(res)
return res
def empty(self) -> bool:
return not self.queue
# 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. 有效的括號
給定一個只包括 '(',')','{','}','[',']' 的字串 s ,判斷字串是否有效。
遍歷過程中,用棧儲存左括號,右括號依次匹配最近的左括號
遍歷過程中無效分三種情況
- 左邊有多餘符號 如 '({}' 最終棧不為空
- 右邊有多餘符號 如 '{})' 中間想匹配發現棧已經為空了
- 中間不匹配,如 '[{(})' 中間發現不匹配直接return False
class Solution:
def isValid(self, s: str) -> bool:
stack = []
for c in s:
if c == '(':
stack.append(')')
elif c == '{':
stack.append('}')
elif c == '[':
stack.append(']')
elif(not stack or stack[-1] != c): #第2,3種情況
return False
else: stack.pop()
# elif c == ')': #冗餘的寫法
# if stack and stack[-1] == ')':
# stack.pop()
# else:
# return False
# elif c == ']':
# if stack and stack[-1] == ']':
# stack.pop()
# else:
# return False
# elif c == '}':
# if stack and stack[-1] = '}':
# stack.pop()
# else:
# return False
return not stack
1047. 刪除字串中的所有相鄰重複項
給出由小寫字母組成的字串 S,重複項刪除操作會選擇兩個相鄰且相同的字母,並刪除它們。
在 S 上反覆執行重複項刪除操作,直到無法繼續刪除。
在完成所有重複項刪除操作後返回最終的字串。答案保證唯一。
思路
按照上述邏輯用棧模擬即可,符合條件的就加入棧中,否則就移除。最終得到一個字元棧,由棧底到棧頂的順序的字元組成即為所求字串,又因為py是中用List模擬的棧,因此很方便地直接將List轉為str即可(對於棧已經是逆序的)
如果是其他語言如CPP,需要將棧元素彈出並且拼接到字串上,還需要反轉。
class Solution:
def removeDuplicates(self, s: str) -> str:
stack = []
for c in s:
# if not stack: #棧為空時
# stack.append(c)
# elif stack and stack[-1] != c:#棧不為空且當前元素不等於棧頂元素
# stack.append(c)
# else:
# stack.pop()
if stack and stack[-1] == c:
stack.pop()
else:
stack.append(c)
return ''.join(stack)
心得體會
棧和佇列的題目中,主要是想到用棧或佇列解決問題後,動手模擬一下遍歷過程中,棧或者佇列的變化情況。在py中,用列表提供有限的操作模擬棧,比如只能訪問棧頂,只能新增移除棧頂元素,均是在列表末尾進行操作([-1],append,pop),由於列表刪除最前面的值時間複雜度為O(N),所以使用deque雙端佇列,如果模擬的是普通佇列,只能從尾進頭出(append,popleft),訪問首元素等([0])。
此外,棧常常用於匹配最近元素或者剛剛訪問過的元素等,如括號匹配和刪除字串中的重複元素。