155. Min Stack

155. Min Stack

這一題是一個物件導向設計題目,要設計出一個棧具有原本的功能,還要可以找到棧中的最小值,其實這個題目還真「簡單」,因為棧本身就是一個陣列,直接使用 min 這個 API 就可以找到最小值了,這裡的時間複雜度只有在 getMin 時達到最高峰為 $$O(n) $$ ,這樣的時間複雜度沒有真的很差,所以這個寫法還可以通過 LeetCode。

class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []

    def push(self, val: int) -> None:
        self.stack.append(val)

    def pop(self) -> None:
        self.stack.pop()

    def top(self) -> int:
        return self.stack[-1]


    def getMin(self) -> int:
        return min(self.stack)

不過很顯然這個不會是面試官要的答案,因為既然然這是一個物件,就會有存在著不斷被取用的可能,例如,如果一直有需要 getMin 的操作,時間複雜度還是會非常的高。這一題要想要怎麼優化的點在於,要怎麼樣不斷的得知與更新最小值?其實我們只要有一個變數例如:self.minVal ,就可以一直保有最小值為何,因為每次一個新的數字放進來棧,就可以更新這個值。不過這個方式是有問題的,那就是當執行出棧時,只有一個變數的話就不能得知更之前的最小值了,既然也需要記得最小值的歷史紀錄,所以這個最小值的記憶方式,也是要用一個棧但是這個棧只有在遇到入棧時的值是最小值的時候,才放進去。

而出棧時,如果遇到當下要出棧的值和當前的最小值相同,那最小值也需要出棧。

class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []
        self.min_stack = []

    def push(self, val: int) -> None:
        self.stack.append(val)
        if len(self.min_stack) == 0:
            self.min_stack.append(val)
        else:
            if self.min_stack[-1] >= val:
                self.min_stack.append(val)

    def pop(self) -> None:
        if not self.min_stack or not self.stack:
            return
        if self.min_stack[-1] == self.stack[-1]:
            self.min_stack.pop()
        self.stack.pop()

    def top(self) -> int:
        return self.stack[-1]


    def getMin(self) -> int:
        return self.min_stack[-1]

這樣的方法,入棧、出棧、查詢最小值的時間複雜度都是 $$O(1)  $$ ,只是會需要額外花費空間複雜度。