[Likou Brush Questions] Day32 - monotone stack topic


monotonic stack

Review of Monotonic Stack Basics: Monotonic Stack and Monotonic Queue

Monotonic stack general template:

int[] stk = new int[N] //Stack<Integer> stk;
int tt = 0;

// 模板1....
for(int i = 0; i < nums.size(); i++){
    
    
    
    while(tt != 0 && stk[tt] > nums[i]){
    
    
		tt --;// 出栈
        .....// 业务处理        
    }
	stk[++ tt] = nums[i];// 数/下标1入栈
}


// 模板2....
for(int i = 0; i < nums.size(); i++){
    
    
    
	while(tt != 0 && stk[tt] <= nums[i]) tt --;// 出栈
	if(tt == 0){
    
    
        .....
    }
	else .....// 业务:(记录左边/右边 第一个比它小/大的数等等业务)
    stk[++ tt] = nums[i];// 数/下标入栈
}

1. Daily temperature

Topic Link: 739. Daily Temperature - LeetCode

Code

class Solution {
    
    
    /**
        思路:从右往左遍历 实现单调递减栈,记录当前每一个数 右边第一个大于它的数的位置(单调递减栈)
     */
     int N = 100010;
     int[] stk = new int[N];
     int tt;
     int[] pos = new int[N];
    public int[] dailyTemperatures(int[] a) {
    
    
        int n = a.length;
        for(int i = n - 1; i >= 0; i --){
    
    
            while(tt != 0 && a[stk[tt]] <= a[i]) tt --;
            if(tt == 0) pos[i] = 0;
            else pos[i] = stk[tt];// 记录右边大于它的第一个数的位置
            stk[++ tt] = i;
        }
        int[] res = new int[n];
        for(int i = 0; i < n; i ++){
    
    
            if(pos[i] == 0){
    
    
                res[i] = 0;
            }else {
    
    
                res[i] = pos[i] - i;// 计算位于右边的第几个
            }
        }
        return res;
    }
}

2. The next larger element I

Topic Link: 496. The Next Bigger Element I - LeetCode

Idea 1: enumeration + hash table

We use a hash table to record the position that appears nums2[]in nums1[i], and then we do two traversals, one loop traversal nums1, the second loop traverses from nums1[i]the corresponding nums2position j, and then find the first one that is greater than nums1[i], mums2[j]if found, jump out directly, otherwise it does not exist .

Code

class Solution {
    
    
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
    
    
        Map<Integer, Integer> mp = new HashMap<>();
        int n = nums1.length;
        int m = nums2.length;

        int[] res = new int[n];
        int cnt = 0;
        for(int i = 0; i < m; i ++) mp.put(nums2[i], i);
        for(int i = 0; i < n; i ++){
    
    
            boolean f = false;
            for(int j = mp.get(nums1[i]); j < m; j ++){
    
    
                if(nums2[j] > nums1[i]){
    
    
                    res[cnt ++] = nums2[j];
                    f = true;
                    break;
                }
            }
            if(!f) res[cnt ++] = -1;
        }
        return res;
    }
}

Idea 2: Monotonic stack + hash table - the same as the daily temperature, the first number on the right that is greater than it is sought. (From right to left) traversal nums2, the monotonic stack finds the first number greater than it on the right, and then records it with a hash table, and finally we can traverse it nums1.

Code

class Solution {
    
    
    int N = 1010;
    int[] stk = new int[N];
    int tt = 0;
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
    
    
        int n = nums1.length;
        int m = nums2.length;

        // 从右往左遍历 找出右边大于它的 第一个数
        Map<Integer, Integer> mp = new HashMap<>();
        for(int i = m - 1; i >= 0; i --){
    
    
            while(tt != 0 && stk[tt] <= nums2[i]) tt --;
            if(tt == 0) mp.put(nums2[i], -1);
            else mp.put(nums2[i], stk[tt]);
            stk[++ tt] = nums2[i];
        }
        int[] res = new int[n];
        for(int i = 0; i < n; i ++){
    
    
            res[i] = mp.get(nums1[i]);
        }
        return res;
    }
}

3. The Next Greater Element II

Topic Link: 503. The Next Bigger Element II - LeetCode

Idea: Traverse from right to left to realize the monotonically decreasing stack, and record the position of the first number greater than it on the right side of each current number. Unlike the previous question, the array of this question is circular.
We can expand the original array to twice the length, which is equivalent to performing two operations on the next larger element I—— (turning the circular array into a chain) (if you don’t understand it, just simulate it manually)

1 2 1 —> 1 2 1 1 2 1

Turning the ring into a chain is equivalent to that we can consider the number to the left of the current number (that is, the next element to the right of the current number in the ring (actually on its left))

Code

class Solution {
    
    

     int N = 100010;
     int[] stk = new int[N];
     int tt;
    public int[] nextGreaterElements(int[] a) {
    
    
        int n = a.length;
        int[] res = new int[n];
        int cnt = 0;
        for(int i = 2 * n - 1; i >= 0; i --){
    
    
            int x = a[i % n];
            int idx = i % n;

            while(tt != 0 && stk[tt] <= x) tt --;
            if(tt == 0) res[idx] = -1;
            else res[idx] = stk[tt];// 记录右边大于它的第一个数的位置
            
            stk[++ tt] = x;// 入栈
        }
        
        return res;
    }
}

4. Catching rainwater

Topic link:

Code

Idea 1: Dynamic programming

insert image description here

Status means:

  • left[i]: Indicates that ithe highest column height on the left side of the column isleft[i]
  • right[i]: Indicates that ithe highest column height on the right side of the column isright[i]

State calculation:

  • left[i] = max(left[i - 1], heigth[i - 1])
  • right[i] = max(right[i + 1], heigth[i + 1])

initialization:

  • left[0] = 0

  • rigth[n - 1] = 0

Code

class Solution {
    
    
    public int trap(int[] height) {
    
    
        int n = height.length;
        int[] left = new int[n + 10];
        int[] right = new int[n + 10];

        // 初始化
        // Arrays.fill(left, 0);
        // Arrays.fill(right, 0);
        left[0] = 0;
        right[n - 1] = 0;

        // 求每根柱子左右两边的最大高度
        for(int i = 1; i < n; i ++){
    
    
            left[i] = Math.max(left[i - 1], height[i - 1]);// 有点DP的意味
        }
        for(int i = n - 2; i >= 0; i --){
    
    
            right[i] = Math.max(right[i + 1], height[i + 1]);
        }

        // 求雨水面积
        int res = 0;
        for(int i = 0; i < n; i ++){
    
    // 计算每一个位置可以接收的水量
            int minH = Math.min(left[i], right[i]);
            if(minH > height[i]){
    
    
                res += (minH - height[i]);
            }    
        }
        return res;
    }
}

The amount of accumulated water in this solution is obtained column by column!

Idea 2: Monotonic stack

monotonically decreasing stack

  • Understand the question, refer to the picture, and pay attention to the nature of the question. When the height of the pillars behind is lower than that of the front, it is impossible to catch rainwater
  • When you find a column higher than the previous one, you can calculate the rainwater received, so use monotonically decreasing

The solution area is calculated horizontally!

Code

/**
    单调栈(递减栈):当遇到大于栈顶元素的柱子(说明可以形成水洼),然后再获取当前洼的高度(栈顶元素就是当前元素)和左边最低的高度(栈顶元素的下一个元素(大于等于当前高度)),即可计算面积(横向的): res += h(min(L, R) - heigth[cur]) * w,否则元素下标入栈
 */
class Solution {
    
    
    int[] stk = new int[2 * 10000 + 10];
    int tt = 0;
    public int trap(int[] height) {
    
    
        int n = height.length;
        int res = 0;
        for(int i = 0; i < n; i ++){
    
    
            while(tt != 0 && height[stk[tt]] < height[i]){
    
    
                int cur = stk[tt --];
                if(tt == 0){
    
    // 栈为空时 就break
                    break;
                }
                int l = stk[tt];
                int r = i;
                int h = Math.min(height[l], height[r]) - height[cur];
                res += h * (r - l - 1);
            }
            stk[++ tt] = i;
        }
        return res;
    }
}

5. The largest rectangle in the histogram

Topic link: 84. The largest rectangle in the histogram - LeetCode

For each position, how do we find the largest matrix it can form? First of all, what is the largest area to find the i-th position?

It is icentered on (determined by the rectangle 高度) height[i]. To maximize the area, it is necessary to find the maximum 宽度. How to find the maximum width is the key:

  • Find 第一个小于 heights[i]the position to the leftleft_i (the position behind left_i to i ( (left_i,i]) can participate heigth[i]in the composition of the height rectangle);

  • Find 第一个小于于 heights[i] the position to the rightright_i (the position in front of right_i to ( [i, right_i)) i can participate heigth[i]in the composition of the height rectangle)

That is, the maximum area isheights[i] * (right_i - left_i -1)

Code

/**
    思路:单调栈
    去求每一个位置i 左右两边第一个小于当前i位置高度的位置, 当前位置的最大矩形 s = (R-L-1) * h[i]
    记录两个特殊临界值:
        当找左边时,栈为空(说明无小于它的,都可以取,我们将其位置即为-1 l[i] = -1)
        当找右边时,栈为空(说明无小于它的,都可以取,我们将其位置即为n r[i] = n)
    我们开两个数组记录每一个位置 左右两边第一个小于它的位置,然后枚举计算最大值即可
    
 */

 /**
    单调递增栈:求左/右边第一个小于它的数的位置(顺序/逆序遍历)
  */

class Solution {
    
    
    int[] stk = new int[100010];
    int tt = 0;
    int[] l = new int[100010];
    int[] r = new int[100010];
    public int largestRectangleArea(int[] heights) {
    
    
        int n = heights.length;

        for(int i = 0; i < n; i ++){
    
    
            while(tt != 0 && heights[stk[tt]] >= heights[i]) tt --;
            if(tt == 0) l[i] = -1;// 我们认为zuo边没有最小时指定为位置-1
            else l[i] = stk[tt];
            stk[++ tt] = i;// 记录左边第一个小于它的位置
        }

        Arrays.fill(stk, 0);
        tt = 0;
        for(int i = n - 1; i >= 0; i --){
    
    
            while(tt != 0 && heights[stk[tt]] >= heights[i]) tt --;
            if(tt == 0) r[i] = n;// 我们认为右边没有最小时指定为位置n
            else r[i] = stk[tt];
            stk[++ tt] = i;
        }
        // for(int i = 0; i < n; i ++){
    
    
        //     System.out.print(l[i] + " ");
        // }
        // System.out.println();
        // for(int i = 0; i < n; i ++){
    
    
        //     System.out.print(r[i] + " ");
        // }        
        int res = 0;
        for(int i = 0; i < n; i ++){
    
    
            res = Math.max(res, (r[i] - l[i] - 1) * heights[i]);
        }
        return res;
    }
}

Guess you like

Origin blog.csdn.net/qq_54773252/article/details/127479821