Day10 棧和佇列Part1

haohaoscnblogs發表於2024-07-26

任務

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])。
此外,棧常常用於匹配最近元素或者剛剛訪問過的元素等,如括號匹配和刪除字串中的重複元素。

相關文章