LeetCode907 Sum of Subarray Minimums(With UnSolvedProblem)

find the sum of (all the subarray’s minimum element) of a given array.

Since the answer may be large, return the answer modulo 10^9 + 7.

this is some kind of stranger problem, please see the example:
Input: [3,1,2,4]
Output: 17
Explanation: Subarrays are [3], [1], [2], [4], [3,1], [1,2], [2,4], [3,1,2], [1,2,4], [3,1,2,4].
Minimums are 3, 1, 2, 4, 1, 1, 2, 1, 1, 1. Sum is 17.

based on the solution, it seems this problem can be solved in a monotonous stack.

now, let’s start from the begining to solve this problem.

so what is a monotonous stack? it’s an increasing or decreasing stack.
how can it be constrcuted?

// example of 
for(int i = 0; i < A.size(); i++){
  while(!in_stk.empty() && in_stk.top() > A[i]){
    in_stk.pop();
  }
  in_stk.push(A[i]);
}

so what can monotonous increasing stack can do?
find the previous less element of each element in a vector with O(n) time. For simplicity of notation, we use abbreviation PLE to denote Previous Less Element.
find the next less element of each element in a vector with O(n) time: For simplicity of notation, we use abbreviation NLE to denote Next Less Element.

and what the monotonous increasing stack applied to current problem?
so, for any fixed element, if we can find the PLE and NLE of this element.
if we denote left[i] is the distance between element A[i] and its PLE.
and we denote right[i] the distance between element A[i] and its NLE.

so the number of subarrays that contains A[i] as the minimum element is left[i] * right[i] (why? because left we can choose is 0~left[i], and right we can choose 0-right[i]. and if we out range that, the minimum element in subarray will not be A[i]).
and with that number of subarrays, and the sum of its contribution of the final results is A[i]*right[i]*left[i].
so the final results will be sum of (A[i] * right [i] * left[i]) where i is 0 to length-1.

and for this problem, in order to calculate the distance, we push the index into monotonous stack instead of that element.

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]) { //why we need to pop even if ple.peek()[0] == A[i]
                ple.pop();
            }
            left[i] = ple.isEmpty()? i+1: i - ple.peek()[1]; //peek() is the first one that smaller than current A[i], use a simple instance to get the i+1 and i-ple.peek()[1] part
            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;
        
    }
    //there is a question: the ple.peek()[0] >= A[i] statement, the == we use or not only effects the time complexity, but will not effect the correctness of my solution. because if we use = then we add more range, so we can sort it quicker.
}
posted @ 2020-05-16 11:57  EvanMeetTheWorld  阅读(12)  评论(0)    收藏  举报