iT邦幫忙

2023 iThome 鐵人賽

DAY 6
0
Software Development

30 天到底能寫多少 Leetcode系列 第 6

[Day6] 今天來看一下 Monotone stack

  • 分享至 

  • xImage
  •  

今天來看的是單調棧(monotonic stack)。

stack 的性質大家應該清楚(後進先出),這邊就不多做解釋。單調棧是在 stack 上多加了一層限制:維護的 stack 必須是遞增或遞減,如果違反規則就一路 pop 出去,直到滿足上述條件為止。

拿來當範例的 496. Next Greater Element I,會檢視陣列每個位置中的元素,然後求出在自己後面、比自己大的下一個數。直觀的算法就是暴力解,直接多次遍歷陣列 O(n) * O(n) = O(n^2)。

如果要使用單調棧的話,這邊要利用一點小技巧,從後往前遍歷,並維持一個遞減的 stack。如果元素有辦法被 push 進 stack 代表有解,沒辦法的話則表示後方沒有比自己更大的數,因此 stack 中所有元素都會被 pop 掉,自己再被 push 進去。

複雜度的話,單次的平均成本比較難計算,不過就 stack 的操作來看,每個 item 最多被 push 一次,也最多被 pop 一次。如果有一次的搜尋成本特別高遍歷了整個 stack,下次的成本就會變成常數,所以複雜度應該在 O(n) 之內吧(如果有錯歡迎指正)。

class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        res = [-1]*len(nums1)
        dic = {nums2[-1]: -1}

        s = [nums2[-1]]

        for i in nums2[:-1][::-1]:
            if i > s[0]:
                s = [i]
                dic[i] = -1
            else:
                while s[-1] < i:
                    s.pop()
                dic[i] = s[-1]
                s.append(i)

        for i in range(len(nums1)):
            res[i] = dic[nums1[i]]

        return res

另一種沒那麼直觀的寫法:

class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        dic = {}
        stack = []

        for item in nums2:
            while stack and item > stack[-1]:
                tail = stack.pop()
                dic[tail] = item

            stack.append(item)

        for item in stack:
            dic[item] = -1

        res = [0 for _ in range(len(nums1))]

        for idx, num in enumerate(nums1):
            res[idx] = dic[num]

        return res



上一篇
[Day5] 區間求和的小小總結
下一篇
[Day7] 從 monotonic stack 到 monotonic queue
系列文
30 天到底能寫多少 Leetcode21
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言