其他分享
首页 > 其他分享> > 单调栈总结

单调栈总结

作者:互联网

单调栈总结+Leetcode实例

单调栈

1.模型识别

  1. 求左边第一个比当前数小/大的数
  2. 求右边第一个比当前数小/大的数
  3. 向前看比当前数都大/小的连续长度–等价于1
  4. 向后看比当前数都大/小的连续长度–等价于2

2.原理

例:求左边第一个比当前数小的数
维护一个单调递增栈,如果i<j, a[i] > a[j], 那么在j以后,a[i]永远不会作为答案被输出,因为a[j]比a[i]小,任意一个j以后的数向前看的时候会被a[j]挡住,看不到a[i]。

3.模板

#include <iostream>
using namespace std;
const int N = 100010;
int stk[N], tt;

int main() {
    int n;
    int x;
    scanf("%d", &n);
    while (n--) {
        cin >> x;
        while (stk[tt] >= x) tt--;
        if (tt) cout << stk[tt] << " ";
        else cout << -1 << " ";
        stk[++tt] = x;
    }
    return 0;
}

4.例题基础版

1) LeetCode 739. 每日温度

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& t) {
        vector<int> res(t.size());
        stack<int> st;
        for (int i = t.size() - 1; i >= 0; i--) {
            while (st.size() && t[i] >= t[st.top()]) st.pop();
            if (st.size()) res[i] = st.top() - i;
            st.push(i);
        }
        return res;
    }
};

2)LeetCode 496. 下一个更大元素 I

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int, int> hash; //用unordered_map哈希表来存,降低时间复杂度
        vector<int> res;
        stack<int> st;
        for (int i = nums2.size() - 1; i >= 0; i--) {
            int cur = nums2[i]; //该循环中反复使用的数,存下来降低时间复杂度
            while(st.size() && st.top() <= cur) st.pop();
            if(st.size()) hash[cur] = st.top();
            else hash[cur] = -1;
            st.push(cur);
        }
        for (int i = 0; i < nums1.size(); i++) {
            res.push_back(hash[nums1[i]]);
        }
        return res;
    }
};

3)LeetCode 503. 下一个更大元素 II

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        stack<int> st;
        int n = nums.size();
        vector<int> res(n);
        nums.insert(nums.end(), nums.begin(), nums.end());
        for (int i = nums.size() - 1; i >= 0; i--) {
            int cur = nums[i];
            while (st.size() && cur >= st.top()) st.pop();
            if (i < n) { //遍历到对应元素再记录
                if (st.empty()) res[i] = -1;
                else {
                    res[i] = st.top();
                }
            }
            st.push(cur);
        }
        return res;

    }
};

4)LeetCode 901. 股票价格跨度

class StockSpanner {
public:
    StockSpanner() {
        
    }
    stack<pair<int, int>> st;

    int next(int price) {
        int w = 1;
        while(!st.empty() && st.top().first <= price) {
            w += st.top().second;
            st.pop();
        }
        st.push(pair<int, int>(price, w));
        return w;
    }
};

5)LeetCode 1019. 链表中的下一个更大节点

class Solution {
public:
    vector<int> nextLargerNodes(ListNode* head) {
        stack<int> st;
        vector<int> res;
        ListNode* cur = head;
        while(cur->next != NULL) {
            res.push_back(cur->val);
            cur = cur->next;
        }
        res.push_back(cur->val);
        vector<int> ans(res.size(), 0);
        for (int i = res.size() - 1; i >= 0; i--) {
            while (!st.empty() && res[i] >= st.top()) st.pop();
            if (!st.empty()) ans[i] = st.top();
            st.push(res[i]);
        }
        return ans;
    }
};

5.例题提高版

1)LeetCode 84. 柱状图中最大的矩形

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int> st1;
        int n = heights.size();
        vector<int> res1(n), res2(n);
        for (int i = 0; i < heights.size(); i++) {
            while(!st1.empty() && heights[i] <= heights[st1.top()]) st1.pop();
            if(!st1.empty()) res1[i] = st1.top();
            else res1[i] = -1;
            st1.push(i);
        }
        st1 = stack<int>();
        for (int i = n - 1; i >= 0; i--) {
            while(!st1.empty() && heights[i] <= heights[st1.top()]) st1.pop();
            if(!st1.empty()) res2[i] = st1.top();
            else res2[i] = n;
            st1.push(i);
        }
        int m = 0;
        for (int i = 0; i < heights.size(); i++) {
            m  = max(m, heights[i] * (res2[i] - res1[i] - 1));
        }
        return m;
    }
};

优化:虽然是常数优化,但是时间复杂度排名一下子提到90%以上了。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int> st1;
        int n = heights.size();
        vector<int> res1(n, -1), res2(n, n);
        for (int i = 0; i < heights.size(); i++) {
            while(!st1.empty() && heights[i] <= heights[st1.top()]) {
                res2[st1.top()] = i;
                st1.pop();
            }
            if(!st1.empty()) res1[i] = st1.top();
            st1.push(i);
        }
        int m = 0;
        for (int i = 0; i < heights.size(); i++) {
            m  = max(m, heights[i] * (res2[i] - res1[i] - 1));
        }
        return m;
    }
};

2)LeetCode 42. 接雨水

class Solution {
public:
    int trap(vector<int>& h) {
        stack<int> st1;
        int n = h.size();
        if (n == 0) return 0;
        int ans = 0;
        for (int i = 0; i < n; i++) {
            while(!st1.empty() && h[i] > h[st1.top()]) {
                int bot = st1.top();
                st1.pop();
                if (st1.empty()) break;
                int left = st1.top();
                ans = ans +  (min(h[left], h[i]) - h[bot]) * (i - left - 1);
            }
            st1.push(i);
        }
        return ans;
    }
};

标签:总结,int,res,st,vector,st1,单调,size
来源: https://blog.csdn.net/qq_43344375/article/details/117436656