单调栈

什么时候用单调栈呢?

通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。

单调栈里存放的元素是什么?

单调栈里只需要存放元素的下标i就可以了,如果需要使用对应的元素,直接nums[i]就可以获取。

 

模板

   heights.push_back(-1);
        int n = heights.size();
        stack<int>st;
        int ans = 0;
        for(int i=0;i<n;i++){
            while(!st.empty()&&heights[i]<heights[st.top()]){
                int index = st.top();st.pop();
                int pre = st.empty()?-1:st.top();
              
                ans = max(ans,???);
            }
            st.push(i);
        }
        return ans;
 

剑指 Offer II 038. 每日温度 - 力扣(LeetCode) (leetcode-cn.com)

 1 class Solution {
 2 public:
 3     vector<int> dailyTemperatures(vector<int>& temperatures) {
 4         int n = temperatures.size();
 5         stack<int>st;
 6         vector<int>ans(n,0);
 7         for(int i = 0;i<n;i++){
 8             while(!st.empty()&&temperatures[i]>temperatures[st.top()]){
 9                 ans[st.top()] = i - st.top();
10                 st.pop();
11             }
12             st.push(i);
13         }
14         return ans;
15     }
16 };
View Code

 496. 下一个更大元素 I - 力扣(LeetCode) (leetcode-cn.com)

 1 class Solution {
 2 public:
 3     vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
 4         int n = nums2.size();
 5         vector<int> tem(n,-1);
 6         vector<int> ans(nums1.size(),-1);
 7         unordered_map<int,int>map;
 8         stack<int> st;
 9         for(int i=0;i<nums2.size();i++){
10             map[nums2[i]] = i;
11             while(!st.empty()&&nums2[i]>nums2[st.top()]){//st.top()是下标不能直接比!!,3,2,1,4,所以是while!
12                 tem[st.top()] = nums2[i];
13                 st.pop();
14             }
15             st.push(i);
16         }
17         for(int i=0;i<nums1.size();i++){
18             // cout<<map[nums1[i]]<<" "<<tem[map[nums1[i]]]<<endl;
19             ans[i] = tem[map[nums1[i]]];
20         }
21         return ans;
22     }   
23 };
View Code

503. 下一个更大元素 II - 力扣(LeetCode) (leetcode-cn.com)

 1 class Solution {
 2 public:
 3     vector<int> nextGreaterElements(vector<int>& nums) {
 4         int n = nums.size();
 5         vector<int>ans(n,-1);
 6         stack<int>st;
 7         for(int i=0;i<2*n;i++){
 8             while(!st.empty()&&nums[i%n]>nums[st.top()%n]){
 9                 ans[st.top()%n] = nums[i%n];
10                 st.pop();
11             }
12             st.push(i%n);
13         }
14         return ans;
15     }
16 };
View Code

 42. 接雨水 - 力扣(LeetCode) (leetcode-cn.com)

 1 class Solution {
 2 public:
 3     int trap(vector<int>& height) {
 4         int n = height.size();
 5         int ans = 0;
 6         stack<int>st;
 7         for(int i=0;i<height.size();i++){
 8             while(!st.empty()&&height[i]>height[st.top()]){
 9                 int low = height[st.top()];st.pop();
10                 if(st.empty())
11                     break;
12                 int y = min(height[i],height[st.top()]) - low;
13                 int x = i-1-st.top();
14                 ans+=x*y;
15             }
16             st.push(i);
17         }
18         return ans;
19     }
20 };
View Code

907. 子数组的最小值之和 - 力扣(LeetCode) (leetcode-cn.com)

 1 class Solution {
 2 private:
 3     const int BASE = 1e9 + 7;
 4 public:
 5     int sumSubarrayMins(vector<int>& arr) {
 6         stack<int> stk;
 7         arr.push_back(0);               // 保证栈中所有元素都会被弹出计算
 8         int len = arr.size();
 9         long res = 0;
10         for ( int i = 0; i < len; ++i ) {
11             while ( !stk.empty() && arr[i] <= arr[stk.top()] ) {
12                 int index = stk.top(); stk.pop();
13                 int prev_index = stk.empty()?-1:stk.top();
14                 int prev_count = index - prev_index - 1; // 数量m
15                 int next_count = i - index - 1;          // 数量n
16                 res += long(arr[index]) * (prev_count + 1) * (next_count + 1) % BASE;
17                 res %= BASE;
18             }
19             stk.push(i);
20         }
21         return res;
22     }
23 };
24 /*
25     数组。存下标就行,下标可以方便取到数值
26     升序序列特殊情况,所以最后加0
27     当前位置可以作为多少个连续子数组的最小值!左边m个数小于nums[cur],右边n个数小于nums[cur],1+m+n+m*n = (m+1)*(n+1)
28     prepre,pre,cur。cur是当前未入栈元素,比栈顶元素小(比栈顶元素大就直接入栈),pre是弹出的栈元素,prepre是弹出栈元素之后的栈顶元素
29     pre-1-prepre = m  ,   cur-1-pre = n 
30 */
View Code

剑指 Offer II 039. 直方图最大矩形面积 - 力扣(LeetCode) (leetcode-cn.com)

 1 class Solution {//思想都是,当前i位置,只是操作之前的数据,然后操作完了i位置数据入栈,等待被后续位置的数操作
 2 public:
 3     int largestRectangleArea(vector<int>& heights) {//[2,1,5,6,2,3,1]最后一个1的时候,先计算了3,再计算了10,2,3,再计算1,10,2,3,只会前面那个1出栈,此时栈空,计算出下标0-5的长度,最后那个1入栈,然后此时到了我构造的-1,和之前一样先算1,然后1出栈栈空算全部
 4         heights.push_back(-1);//因为题目数据最小是0
 5         int n = heights.size();
 6         int ans = 0;
 7         stack<int> st;
 8         for(int i=0;i<n;i++){
 9             while(!st.empty()&&heights[i] < heights[st.top()]){
10                 int index = st.top();st.pop();//以index位置的高度为矩形高时,最大矩形的情况,
11                 int pre = st.empty()?-1:st.top();//栈为空表示没有数据比index的高度要低了,也就是0-index这块都可以以index为高
12                 int x = i-1-pre;//i-1是右边界不包括i,左边界不包括pre。要在pre右边,因为单调递增栈heights[pre]<heights[index]
13                 int y = heights[index];
14                 ans = max(ans,x*y);
15             }
16             st.push(i);
17         }
18         return ans;
19     }
20 };
21 /*
22     对于任意位置,找到以这个位置为高的最大面积(往左往右延申)
23 */
View Code

 

posted @ 2022-03-22 15:45  剩下的交给时间就好  阅读(39)  评论(0编辑  收藏  举报