模板问题:Mono Stack/Queue (LeetCode739: Daily Temperatures)

我们之前专们解决过这类问题
https://blog.csdn.net/weixin_44337445/article/details/106157119
现在我们来宏观的复习一下:
所谓的mono stack/queue,就是我们保持stack里面的元素递增或者递减。
也就是说 我们可以随时直到当前元素的PLE或者NLE(previous less element/next less element)元素的位置
以:LC907为例:
Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarray of A.
那么mono stack是如何apply到这上面的呢?
针对每一个元素 我们找他的PLE离A[i]的距离 写到ple[i]中
找他的NLE离A[i]的距离 写到nle[i]中
然后本题的最后的答案就是Sum(A[i] * ple[i] * nle[i]) 意思就是以A[i]作为最小的值的subarray的个数为ple[i]*nle[i]个。
仔细观察下面纯净版的代码:
核心就是构建ple和nle stack

class Solution {
    public int sumSubarrayMins(int[] A) {
        Stack<int[]> ple = new Stack<>(); //int[0],int[1] = A[i], i
        Stack<int[]> nle = new Stack<>();
        
        int[] left = new int[A.length];
        int[] right = new int[A.length];
        
        //construct ple
        for (int i = 0; i<A.length; i++) {
            while (!ple.isEmpty() && ple.peek()[0] >= A[i]) { 
                ple.pop();
            }
            left[i] = ple.isEmpty()? i+1: i - ple.peek()[1]; 
            ple.push(new int[]{A[i], i});
        }
        
        //construct nle
        for (int i = A.length - 1; i>=0; i--) {
            while (!nle.isEmpty() && nle.peek()[0] > A[i]) { 
                nle.pop();
            }
            right[i] = nle.isEmpty() ? A.length - i: nle.peek()[1] - i;
            nle.push(new int[]{A[i], i});
            
        }
        
        int ans = 0; 
        int mod = 1000000007;
        for (int i = 0; i<left.length; i++) {
            ans = (ans + A[i] * left[i] * right[i]) % mod;
        }
        return ans;
        
    }
}

接下来再看看下面的注释版:

class Solution {
    public int sumSubarrayMins(int[] A) {
        Stack<int[]> ple = new Stack<>(); //int[0],int[1] = A[i], i
        Stack<int[]> nle = new Stack<>();
        
        int[] left = new int[A.length];
        int[] right = new int[A.length];
        
        //construct ple
        for (int i = 0; i<A.length; i++) {
            while (!ple.isEmpty() && ple.peek()[0] >= A[i]) { //将大于等于当前值的全部pop,也就是说 只留下第一个小于A【i】的
                ple.pop();
            }
            left[i] = ple.isEmpty()? i+1: i - ple.peek()[1]; //如果是空就说明i前面的都小于i 所以这个长度为(i+1)(因为我们是包含了i的)
            ple.push(new int[]{A[i], i}); //push进去当前的
        }
        
        //construct nle
        for (int i = A.length - 1; i>=0; i--) {
            while (!nle.isEmpty() && nle.peek()[0] > A[i]) { 
                nle.pop();//一直Pop 直到第一个小于等于A[i]的
            }
            right[i] = nle.isEmpty() ? A.length - i: nle.peek()[1] - i;
            nle.push(new int[]{A[i], i}); //跟之前nle的解释一样
            
        }
        
        int ans = 0; //
        int mod = 1000000007;
        for (int i = 0; i<left.length; i++) {
            ans = (ans + A[i] * left[i] * right[i]) % mod;
        }
        return ans;
        
    }
}

下面来看一下LC739
就是完完全全按照907来的

class Solution {
    public int[] dailyTemperatures(int[] T) {
        //典型的mono stack问题
        //之前我们需要求ple/nle 现在我们需要求next larger element.
        //思路上并没有什么不同
        LinkedList<int[]> nle = new LinkedList<>();
        int n = T.length;
        int[] right = new int[n];
        
        for (int i = n - 1; i >= 0; i--) {
            while (!nle.isEmpty() && nle.peek()[0] <= T[i]) { //keep pop until find the first one who is larger than T[i]
                nle.pop();
            }
            right[i] = nle.isEmpty() ? 0: nle.peek()[1] - i; //这儿要尤其注意 我们现在要的是长度 如果没有这样的东西存在 就说明没有符合条件的 所哟定为0.
            nle.push(new int[]{T[i], i});
        }
        return right;
    }
}
posted @ 2020-12-19 05:31  EvanMeetTheWorld  阅读(25)  评论(0)    收藏  举报