One article to completely understand the monotonic stack! ! !

Preface

        After recently sorting out the middleware, Lizhi brushed up on the algorithm while learning the project, and brushed up on strings, double pointers, stacks and queues, and monotonic stacks in the code capriccio. Among them, the more difficult one is the monotonic stack, so it is necessary to sort out an article to review the relevant knowledge of the monotonic stack~ I hope you can gain something after the review!


Article directory

Preface

1. Monotone stack

2. Classic examples

2.1 Leecode739. Daily temperature

2.2 Leecode42. Catching rainwater

2.3 Leecode84. The largest rectangle in the column chart

Summarize


1. Monotone stack

        I believe everyone, like Lizhi, has understood the data structure of the stack. Hehehe, the stack is a first-in, last-out data structure. In C++, you can use the stack container adapter to select the underlying implementation of this data structure, such as list, vector, deque, etc. By default, STL uses a double-ended queue Deque to match the bottom layer of the stack, so I won’t go into details here. A monotonic stack, as the name suggests, is a monotonic stack. It is actually a variant of the data structure of the stack. The elements in the stack are sorted from small to large, or from large to small. In other words, there are two types of monotonic stacks by default: monotonically increasing stacks and monotonically decreasing stacks.

Application scenarios:

Monotonic stacks are generally used in scenarios such as: in a set of elements nums, find the first largest|smallest element to the right of any element. Of course, you can also use it to find the one on the left. 

Some friends may say: Just use direct violence, but direct violence may still time out. The time complexity of a monotonic stack is O(n).

Following the code caprice sequence, the first question on monotonic stack is Leecode739. Daily temperature . This question is a template question of the monotonic stack series.


2. Classic examples

2.1 Leecode739. Daily temperature

Topic description:

        Given an array of integers  temperatures representing daily temperatures, return an array  answer where,  answer[i] for  i day th, the number of days after which the next higher temperature occurs. If the temperature does not rise after this, use it in that location 0 instead .

Input example:

temperatures = [73,74,75,71,69,72,76,73]

Output sample:

[1,1,4,2,1,1,0,0]

        After reading the question, should we choose a monotonically increasing monotonic stack or a monotonically decreasing monotonic stack to simulate? Lizhi feels that it is still necessary to simulate it manually. After simulating it, you will probably understand the entire implementation process. First, Litchi manually simulates an increasing monotonic stack.

Increasing monotonic stack

We give a set of data to simulate the process of solving monotonic stack problems 

        First, we need to define a stack to maintain and record the subscript of each element in the original container, and a vector container to record the results we need. Before starting the traversal, you need to push the first element in the original vector container template to the stack. This is to facilitate the subsequent comparison logic. The traversal of the for loop will start from 1. In order to ensure that the stack is monotonically increasing, if the currently traversed element is greater than the element corresponding to the subscript of the top element of the stack, we need to pop the top element of the stack, but before popping, we can find that, For the element on the top of the stack, the nearest maximum value we require is actually the element we are currently traversing . According to the question, what is required is the nearest higher temperature. Then we need to update our result in real time, so we have result [stack.top( )] = i-stack.top(); When the currently traversed element is less than or equal to the element corresponding to the subscript of the top element of the stack, it meets the requirement of monotonically increasing, so you can just push() directly. So after simulating it again, we found that using a monotonically increasing monotonic stack can be used to find the nearest larger element to the right of each element of the array!

class Solution {
public:
    //单调栈来实现
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        stack<int> stack;
        vector<int> result(temperatures.size(),0);
        //先把头元素加进去
        stack.push(0);
        for(int i=1;i<temperatures.size();i++){
            if(temperatures[i]==temperatures[stack.top()]){
                stack.push(i);
            }else if(temperatures[i]<temperatures[stack.top()]){
                stack.push(i);
            }else{
                while(!stack.empty() && temperatures[i]>temperatures[stack.top()]){
                    result[stack.top()] = i-stack.top();
                    stack.pop();
                }
                stack.push(i);
            }
        }
        return result;
    }
};

Decreasing monotonic stack

        After reading the simulation of the increasing monotonic stack, we continue to try to simulate the process of decreasing the monotonic stack. Also in order to ensure that the stack is monotonically decreasing, for each traversed element i, if template[i] is greater than or equal to the value corresponding to the top element of the stack, just push it directly into the stack; if it is less than the value corresponding to the top element of the stack value, we need to pop the top element of the stack. Before popping, we can still easily figure out: the currently traversed element is actually the nearest right minimum value pressed in the stack that is greater than the element! It is easier to understand, because the stack is monotonically decreasing. If an element a in the stack is smaller than the currently traversed element b, then a will naturally be pushed above b after the while loop is executed. So back to the above question, the result we get is actually to find the next lower temperature for each weather.

demo example

class Solution {
public:
    //单调栈来实现
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        stack<int> stack;
        vector<int> result(temperatures.size(),0);
        //先把头元素加进去
        stack.push(0);
        for(int i=1;i<temperatures.size();i++){
            if(temperatures[i]==temperatures[stack.top()]){
                stack.push(i);
            }else if(temperatures[i]>temperatures[stack.top()]){
                stack.push(i);
            }else{
                while(!stack.empty() && temperatures[i]<temperatures[stack.top()]){
                    result[stack.top()] = i-stack.top();
                    stack.pop();
                }
                stack.push(i);
            }
        }
        return result;
    }
};

2.2 Leecode42. Catching rainwater

Topic description:

Given  n a non-negative integer representing  1 the height map of each column with a width of , calculate how much rainwater the columns arranged in this way can catch after it rains.

Input:
height = [0,1,0,2,1,0,1,3,2,1,2,1]

Output
6

        To calculate the amount of rainwater that can be received, we must find the corresponding length and width of the blue area in the picture. For the currently traversed element, we use it as a basis to find the latest higher values ​​on the left and right respectively. This returns to the scene of the previous problem - solving the daily temperature. What we need to pay attention to is the processing of the latest higher value on the left here: Since the most recent higher value on the right uses an increasing monotonic stack, if the currently traversed element is higher than the element corresponding to the subscript at the top of the stack, then The element below the top of the stack may be the next higher value on the left that we require. Therefore, we need to save the top element of the stack and pop it out so that we can get the elements below the top of the stack.

Code example:

class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> sta;
        sta.push(0);
        int sum = 0;
        for(int i=1;i<height.size();i++){
            if(height[i] < height[sta.top()]){
                sta.push(i);
            }else if(height[i] == height[sta.top()]){
                sta.push(i);
            }else{
                while(!sta.empty() && height[i]>height[sta.top()]){
                    int m = sta.top();
                    sta.pop();
                    if(!sta.empty()){
                        int h = min(height[i],height[sta.top()]) - height[m];
                        int w = i-sta.top()-1;
                        sum += h*w;
                    }
                }
                sta.push(i);
            }
        }
        return sum;

    }
};

 In the demo, there are actually relatively few changes in daily temperature, haha~

2.3 Leecode84. The largest rectangle in the column chart

Question description:
Given  n  non-negative integers, they are used to represent the height of each column in the histogram. Each column is adjacent to each other and has a width of 1.

Find the maximum area of ​​the rectangle that can be drawn in this histogram.

enter:

heights = [2,1,5,6,2,3]


Output:

10

        Finding the largest rectangle in a column chart is actually a question similar to the problem of catching rainwater, except that it is looking for the maximum area of ​​the bulge. Therefore, the element in the middle must be larger than the elements on both sides, so the decreasing monotonic method must be used. stack. Different from the problem of catching rainwater, this question is to use the top element of the stack as the basis to find the first number on the left and right sides that is smaller than it . The value of left, right, right-left-1 is a rectangle based on the height of the reference axis. The width of the area. The height must be our current benchmark - the top element of the stack, so here we also need a variable to record the size of the top element of the stack and the subscript in the original array.

demo example:

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        //这里需要在前后加上0避免在单调递减栈中阻塞的情况
        stack<int> sta;
        int result = 0;
        heights.insert(heights.begin(),0);
        heights.push_back(0);
        sta.push(0);
        //本题目采用的是单调递减栈
        for(int i=1;i<heights.size();i++){
            if(heights[i]>heights[sta.top()]){
                sta.push(i);
            }else if(heights[i] == heights[sta.top()]){
                sta.push(i);
            }else{  
                while(!sta.empty() && heights[i] < heights[sta.top()]){
                    int mid = sta.top();
                    sta.pop();
                    if(!sta.empty()){
                        int left = sta.top();
                        int right = i;
                        int h = heights[mid];
                        int w = right-left-1;
                        result = max(result,w*h);
                    }
                }
                sta.push(i);
            }
        }
        return result;
    }
};

Summarize

        Above, Lizhi gives the simulation derivation of two types of monotonic stacks, and also gives Lizhi's own understanding and comparison with corresponding examples. The daily temperature undoubtedly needs to be carefully polished. The rainwater problem and finding the maximum rectangle are the applications of increasing monotonic stack and decreasing monotonic stack respectively. In fact, the most basic template is still the daily temperature problem-solving template hahahaha. I hope the lychee combing will be helpful to my friends, hahahaha~~~

Today has become the past, but we still look forward to the future tomorrow! I am Litchi, and I will accompany you on the road of technological growth~~~

If the blog post is helpful to you, you can give Lizhi three clicks. Your support and encouragement are Lizhi’s biggest motivation!

If the content of the blog post is incorrect, you are also welcome to criticize and correct it in the comment area below! ! !

Guess you like

Origin blog.csdn.net/qq_62706049/article/details/133176388
Recommended