「程式碼隨想錄演算法訓練營」第四十一天 | 單調棧 part1

云雀AC了一整天發表於2024-08-19

739. 每日溫度

題目連結:https://leetcode.cn/problems/daily-temperatures/
文章講解:https://programmercarl.com/0739.每日溫度.html
題目難度:中等
影片講解:https://www.bilibili.com/video/BV1my4y1Z7jj/
題目狀態:看題解

思路:

定義一個單調棧,該棧存放下標,規則是要保持其下標對應的溫度值從棧底到棧頭是單調遞減的。再定義一個和題目陣列大小相等的陣列ans存放結果,初始化為0。具體步驟如下:

  1. 先將第一個元素的下標存入棧中。
  2. 迴圈遍歷溫度陣列:
    • 若當前溫度小於等於棧頭元素的溫度,將當前溫度的下標壓入棧。
    • 若當前溫度大於棧頭元素的溫度,將棧中比當前溫度低的元素都彈出,在彈出的時候將其壓入結果陣列中(i-st.top()),直到棧頭大於當前溫度,將當前溫度的下標壓入棧。
  3. 遍歷結束後,返回結果陣列。

程式碼:

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        int len = temperatures.size();
        stack<int> st;
        vector<int> ans(len, 0);
        st.push(0);
        for(int i = 1; i < len; ++i) {
            if(temperatures[i] <= temperatures[st.top()]) st.push(i);
            else {
                while(!st.empty() && temperatures[i] > temperatures[st.top()]) {
                    ans[st.top()] = i - st.top();
                    st.pop();
                }
                st.push(i);
            }
        }
        return ans;
    }
};

496. 下一個更大元素 I

題目連結:https://leetcode.cn/problems/next-greater-element-i/
文章講解:https://programmercarl.com/0496.下一個更大元素I.html
題目難度:簡單
影片講解:https://www.bilibili.com/video/BV1jA411m7dX/
題目狀態:用其他方法過的,看題解學習一下單調棧的方法

思路一:巢狀迴圈

非常傳統的方法,遍歷整個nums1,每遍歷一個元素就在nums2中找到對應的元素下標,然後再在nums2中從下標位置開始向後遍歷,直到找到一個比元素大的元素,將其值填入結果陣列中並跳出迴圈,若找不到直接返回,因為這個結果陣列初始化的時候將其全部值初始化為-1了。

程式碼一:

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        int len1 = nums1.size(), len2 = nums2.size();
        vector<int> ans(len1, -1);
        for(int i = 0; i < len1; ++i) {
            auto it = find(nums2.begin(), nums2.end(), nums1[i]);
            int index = distance(nums2.begin(), it);
            for(int j = index; j < len2; ++j) {
                if(nums2[j] > nums1[i]) {
                    ans[i] = nums2[j];
                    break;
                }
            }
        }
        return ans;
    }
};

消耗:
image

思路二:單調棧

nums1壓入一個unordered_map<int, int>中,主要原因是它的查詢和增刪效率是最優的。
然後維護一個單調棧st,這個棧從棧底到棧頭是單調遞減的,用來遍歷nums2,當遇到元素比棧頭元素大的時候,就判斷一下棧頭元素是否在nums1中存在,如果存在就表示其後面有比棧頭元素高的元素,將這個元素值更新到結果陣列中。

程式碼二:

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        int len1 = nums1.size(), len2 = nums2.size();
        stack<int> st;
        vector<int> ans(len1, -1);
        if(len1 == 0) return ans;
        unordered_map<int, int> umap;
        for(int i = 0; i < len1; ++i) {
            umap[nums1[i]] = i; // key:下標元素,value:下標
        }
        // 將nums2壓入單調棧
        st.push(0);
        for(int i = 1; i < len2; ++i) {
            if(nums2[i] <= nums2[st.top()]) st.push(i);
            else {
                while(!st.empty() && nums2[i] > nums2[st.top()]) {
                    if(umap.count(nums2[st.top()]) > 0) { // 看看umap中是否存在該元素
                        int index = umap[nums2[st.top()]]; // 根據map找到nums2[st.top()]在nums1中的下標
                        ans[index] = nums2[i];
                    }
                    st.pop();
                }
                st.push(i);
            }
        }
        return ans;
    }
};

消耗:

image

503. 下一個更大元素 II

題目連結:https://leetcode.cn/problems/next-greater-element-ii/
文章講解:https://programmercarl.com/0503.下一個更大元素II.html
題目難度:中等
影片講解:https://www.bilibili.com/video/BV15y4y1o7Dw/
題目狀態:自己的思路沒透過,好奇怪,chatGPT幫忙修改了一下,直接把我思路改了

思路:

  1. 迴圈陣列處理

    • 為了模擬迴圈陣列,我們遍歷陣列兩次。這樣可以確保每個元素都能找到它的下一個更大元素,即使這個元素在陣列的末尾。
  2. 使用棧

    • 棧用來儲存索引,而不是元素值。這使我們能夠直接在結果陣列中更新對應位置的值。
  3. 遍歷陣列

    • 在每次遍歷中,我們檢查當前元素是否大於棧頂元素對應的值。
    • 如果是,則更新結果陣列中棧頂元素索引對應的值,並彈出棧頂。
    • 如果當前索引在陣列的前半部分(即小於 len),我們將其索引壓入棧中。
  4. 結果更新

    • 透過這種方式,所有元素的下一個更大元素都會在結果陣列中被正確更新。

程式碼:

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        int len = nums.size();
        stack<int> st;
        vector<int> ans(len, -1);
        for(int i = 0; i < 2 * len; ++i) {
            int num = nums[i % len];
            while(!st.empty() && nums[st.top()] < num) {
                ans[st.top()] = num;
                st.pop();
            }
            if(i < len) st.push(i);
        }
        return ans;
    }
};

消耗:

image

相關文章