leetcode-屢試不爽的單調(diào)(遞增\遞減)棧

有一些關(guān)于數(shù)組中數(shù)值比較類型的題目,通常O(n2)的解法是可以得到正確的解,但是,當(dāng)數(shù)組范圍較大時(shí),需要盡可能采取O(n)的解法。單調(diào)棧通常是一個(gè)很好的算法。
單調(diào)棧的算法,在leetcode中有大量的題目涉及,該算法確實(shí)是一個(gè)非常高效是算法。
原理如下:
1)單調(diào)棧的棧中存儲的元素為數(shù)組索引,通常用以解決無序數(shù)組按一定條件進(jìn)行遍歷的相關(guān)問題。
2)以單調(diào)遞減棧為例,stack[i]存儲的是數(shù)組索引,單調(diào)棧的種類有兩個(gè):
在一個(gè)數(shù)組上從下標(biāo)0開始從左到右遍歷,若元素a小于棧頂元素則壓入。對于棧中元素s[i]而言,s[i]為區(qū)間[0, s[i + 1])的最小值的索引;
在一個(gè)數(shù)組上從下標(biāo)0開始從左到右遍歷,若元素e大于等于棧頂元素則將棧頂元素彈出直到e小于棧頂元素再入棧,s[i]為區(qū)間(s[i - 1], pos]的極大值的索引,pos為當(dāng)前遍歷位置。
下面這個(gè)帖子,講的比較好,供參考。
https://blog.csdn.net/liujian20150808/article/details/50752861
leetcode相關(guān)題目
496. 下一個(gè)更大元素 I
該題應(yīng)該是單調(diào)遞增棧的模板代碼。
通過單調(diào)遞增棧,為num2數(shù)組中的每個(gè)元素找到它的下一個(gè)最大元素。由于num1是num2的子數(shù)組,所以選擇map存儲num1的處理結(jié)果。

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        stack<int> s;
        unordered_map<int, int> m;
        for (int n : nums2) {
            while (s.size() && s.top() < n) { //一直在走下坡路,突然遇到一個(gè)上坡,看看是否可以逆襲
                m[s.top()] = n;
                s.pop();
            }
            s.push(n);
        }
        vector<int> ans;
        for (int n : nums1) ans.push_back(m.count(n) ? m[n] : -1);
        return ans;
    }
};

962. 最大寬度坡

題解

最大坡

代碼

class Solution {
public:
    int maxWidthRamp(vector<int>& A) {
        stack<int> s;
        int ans = 0;
        s.push(0);
        for (int i = 1; i < A.size(); i++) {
            if(A[i] < A[s.top()])
            s.push(i);
        }
        for (int i = A.size() - 1; i >= 0; i--) {
            while (!s.empty() && A[i] >= A[s.top()]) {
                ans = max(ans, i - s.top());
                s.pop();
            }
            if ( i < ans) break;
        }
        return ans;
    }
};

42. 接雨水

題解

圖示

這道題的關(guān)鍵在于求解兩個(gè)柱子之間的空間面積。
說下想法:
1)兩個(gè)柱子之間的距離 高度如何求解
2)如何排除類似 0 0 0 0 1這種不可接雨水的情況
基于單調(diào)棧的算法我一開始是想到了的,并且計(jì)算出了距離,但是一直沒想好怎么求解高度,為了加深記憶,我畫個(gè)圖來分析高度的求解方法。


計(jì)算面積思維導(dǎo)圖

從分析可以看出,單調(diào)??赡苌婕暗饺齻€(gè)索引位置
1)數(shù)組中當(dāng)前正在比較的索引
2)棧頂元素
3)棧中做回溯,通過回溯找到一個(gè)合適的位置

代碼

class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> s;
        int res = 0;
        int high = 1;
        for (int i = 0; i < height.size(); i++) {
            while (!s.empty() && height[s.top()] <= height[i]) {
                int top = s.top();s.pop();
                if (s.empty()) break;
                int length = i - s.top() - 1;
                int high = min(height[i], height[s.top()]) - height[top];
                res += length * high;
            }
            s.push(i);
        }
        return res;
    }
};

84. 柱狀圖中最大的矩形

題解

題解

代碼

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        if (heights.empty()) return 0;
        stack<int> sk;
        int area = 0;
        heights.push_back(0);
        for (int i = 0; i < heights.size(); i++) {
            while (!sk.empty() && heights[i] < heights[sk.top()]) {
                int top = sk.top();
                sk.pop();
                int w = sk.empty() ? i : i - sk.top() - 1;
                area = max(area, w * heights[top]);
            }
            sk.push(i);
        }
        return area;     
    }
};

單調(diào)棧算法總結(jié)

1)遞增棧,還是遞減棧的選擇,可以考慮用排除思想
2)算法融入,通常單調(diào)??梢越鉀Q的問題中,用貪心算法比較多。
3)三個(gè)關(guān)鍵點(diǎn),1、當(dāng)前索引 2、棧頂出棧元素 3、回溯元素
4)元素是否需要全部出棧,如果需要則需要構(gòu)造條件完成元素出棧。
5)面積相關(guān)問題中,關(guān)于高度和寬度的求解通常容易犯糊涂,這部分還是要多想想。
好啦,經(jīng)過上面幾道題的訓(xùn)練,關(guān)于棧以及單調(diào)棧的應(yīng)用,應(yīng)該算比較有數(shù)了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容