[Data Structure] Monotonic Stack

Monotonic stack

This is the author's first blog, due to the limitations of the author's own level. The words may not be accurate enough, the sentences may not be fluent, and the code level may not be good, please point it out, thank you!

We all know that the stack (Stack) is a first-in-last-out data structure, and the monotonic stack is built on the basis of the stack, which is different from the ordinary stack.

The elements in the stack have always maintained a monotonically increasing/monotonically decreasing relationship

For example, the elements in the monotonically increasing stack are monotonically increasing from the bottom of the stack to the top element (0~n-1), and the elements in the monotonically decreasing stack are all monotonically decreasing.

In order to deepen the impression, we can first take the monotonically decreasing stack as an example, look at an example~

There is a set of numbers nums[6] = {10,1,8,12,6,4} according to the following rules:

  1. If the stack is empty/the number being processed is less than the number at the top of the stack, it is pushed into the stack;
  2. If the number being processed is greater than the number on the top of the stack, the top element of the stack is popped out of the stack, and then the judgment continues.

OK, first we empty the stack, and then read one by one.

  1. First read 10, the stack is empty at this time, 10 is pushed into the stack, and the current state of the stack: {10}

  2. Read 1, the top element of the stack is 10, 1<10, 1 is pushed into the stack, the state of the stack: {10, 1}

  3. Read 8, the top element of the stack is 1, 8>1, then we pop 1 out of the stack;

    Continue to judge, 8<10, so 8 is pushed into the stack, the state of the stack: {10, 8}

  4. Read the number 12, the top element of the stack is 8, and 12>8, pop 8 out of the stack;

    Continue to judge, 12>10, so 10 is popped from the stack. At this time, the stack is empty, and 12 is pushed into the stack: {12}

  5. Read 6, 6<12, push to the stack; {12, 6}

  6. Read 4, 4<6, push 4 into the stack. {12, 6, 4}

After reading this, I believe that the reader has a little understanding of the basic operations of the monotonic stack, then, what is the use of the monotonic stack?

Still look at the above example, suppose we use the monotonic stack to process the above array and get another array (assuming the array is named arr, and initialize the array to 0), stipulate: after processing each number (nums[i]) , If nums[i] is kept in the stack, then arr[i] is incremented by 1, then after processing the entire array, the arr array obtained should be: {3,1,1,3,2,1}, no It is difficult to find that the meaning of arr[i] is:

Starting from the i-th element, the number of consecutive smaller numbers from left to right

Through the data structure of the monotonic stack, we can easily get this array (it is easy to know the number near an element and the size relationship between it) (only O(n) time). Therefore, if you often need to determine the size relationship between the elements before and after the array in the problem, you may wish to use a monotonic stack data structure.

In this way, the reader may not have a thorough understanding or a deep impression, so let’s take a look at a sample question together~

Catch rain

Given n non-negative integers representing the height map of each column with a width of 1, calculate how much rain water can be received by the columns arranged in this way.

Example 1:

[External link image transfer failed. The source site may have an anti-leech link mechanism. It is recommended to save the image and upload it directly (img-KKSNHLab-1603381702730)(C:\Users\86159\Desktop\rainwatertrap.png)]

Input: height = [0,1,0,2,1,0,1,3,2,1,2,1] Output: 6 Explanation: The above is composed of the array
[0,1,0,2,1,0 ,1,3,2,1,2,1] represents the height map. In this case, 6 units of rain can be received (the blue part represents rain).

Example 2:

Input: height = [4,2,0,3,2,5]
Output: 9

After reading the topic, we can analyze it first, according to the amount of water that can be held at the i-th position from the left = min (the height of the highest column on the left of the column, the height of the highest column on the right of the column)-the column the height of.

method one:

Enumerate the height of the highest column on the left and the height of the highest column on the right of each column violently from left to right, and add the final result. The time complexity is O(n²).

Method Two:

It is not difficult to see that we need to often compare the height of the column at each position with the height of its left and right columns, so we might as well build a monotonous stack to simulate this process:

(For the sake of convenience, we assume that the height of the column currently read is heights[i], the number of the column stored in the stack (from left to right 0~n-1), and the height of the stack is Size)

  1. If the stack is empty (Size==0) or the height of the column is less than the height of the column at the top of the stack (heights[i] <heights[stack[Size-1]]), then the stack is pushed;
  2. If the height of the column is greater than or equal to the height of the column at the bottom of the stack (the tallest column on the left at this time) (heights[i] >= heights[stack[0]]), each grid in the stack except the bottom of the stack can hold more heights[ stack[0]]-heights[stack[j]] units of rain;
  3. If the height of the column is greater than the height of the column at the top of the stack and smaller than the height of the column at the bottom of the stack (heights[i] >= heights[stack[Size-1]]), the column corresponding to the element at the top of the stack can hold more heights[i]-heights[ stack[Size-1]] units of rain. (After updating the value of the answer ans, we might as well make the height of the column corresponding to the top element of the stack equal to heights[i])

As a demonstration of the first example above:

  1. Read in heights[0] = 0 and push to the stack.Alt

  2. Read in height heights[1] = 1, greater than the element at the bottom of the stack, pop the bottom element of the stack (because there is only one element in the stack at this time, so there is no need to operate on ans), and then heights[1] is pushed onto the stack.Alt

  3. Read element heights[2] = 0, which is smaller than the top element on the stack, and push it to the stack.
    Alt

  4. Read the element heights[3] = 2, which is greater than the element at the bottom of the stack, and pop all elements in the stack. At this time, because heights[2] = 0 and heights[1] = 1, you can hold 1-0=1 more units The rain will be ans + 1. Then push heights[3] onto the stack.
    Alt

  5. Read the element heights[4] = 1, and push it to the stack. Read the element heights[5] = 0 and push it to the stack.
    Alt

  6. Read in the element heights[6] = 1, where heights[6]> heights[5] and heights[6] <heights[3]. After adding heights[6]-heights[5] to ans, let heights[5] = heights[6]. Continue to judge, heights[4] = heights[6]. heights[6] into the stack.
    Alt

  7. Read in the element heights[7] = 3, where heights[7]> heights[3] (the bottom element of the stack). So pop all the elements in the stack, add heights[4], heights[5], heights[6] to the difference between heights[3] and update ans. Then push heights[7] onto the stack.
    Alt

  8. The following steps are just repeating the previous ones, so skip it here. It is worth noting that there are still five elements in the final stack, but because the right side is empty and can't hold water, there is no need to pop out of the stack, just keep it as it is.

    Code implementation (C language):

    int trap(int* height, int heightSize){
        int stack[1000];
        int top = 0,i;
        int ans = 0;
        for(i=0;i<heightSize;i++){
            if(top==0){	//如果栈为空,直接进栈
                stack[0] = i;
                top++;
            }else if(height[i] >= height[stack[0]]){ //如果读到元素大于栈底元素高度,将栈置空后进栈
                int j;
                for(j=1;j<top;j++){
                    ans += height[stack[0]] - height[stack[j]];
                    height[stack[j]] = heights[stack[0]]
                }
                stack[0] = i;
                top = 1;
            }else{
                int j=1;
                while(height[i]>height[stack[top-j]]){ 
                    ans += height[i] - height[stack[top-j]];
                    height[stack[top-j]] = height[i];
                    j++;
                }
                stack[top] = i;
                top++;
            }
        }
        return ans;
    }
    

Limited to the author's level, there may be errors or omissions in the article or code, readers are welcome to correct me, thank you!

Guess you like

Origin blog.csdn.net/April__CSDN/article/details/109233363