0907-sum-of-subarray-minimums

Try it on leetcode

Description

Given an array of integers arr, find the sum of min(b), where b ranges over every (contiguous) subarray of arr. Since the answer may be large, return the answer modulo 109 + 7.

 

Example 1:

Input: arr = [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.

Example 2:

Input: arr = [11,81,94,43,3]
Output: 444

 

Constraints:

  • 1 <= arr.length <= 3 * 104
  • 1 <= arr[i] <= 3 * 104

Solution(Python)

class Solution:
    def __init__(self):
        self.mod = (10**9 )+7
        
    def sumSubarrayMins(self, arr: List[int]) -> int:
        return self.dp(arr)
        
    # Time Complexity: O(n^3)
    # Space Complexity: O(1)
    def bruteforce(self, arr: List[int]) -> int:
        n = len(arr)
        res = 0
        
        for end in range(n):
            for start in range(n):
                min_ = float('-inf')
                for i in range(start,end+1):
                    min_ = min(min_,arr[i])
                res += (min_&self.mod)
        
        
        return res
  
    # Time Complexity: O(n^2)
    # Space Complexity: O(1)
    def betterbruteforce(self, arr: List[int]) -> int:
        n = len(arr)
        res = 0
        
        for start in range(n):
            min_=arr[start]
            for i in range(start,n):
                min_ = min(min_,arr[i])
                res += (min_%self.mod)
                
        return res
    
    # Time Complexity: O(n)
    # Space Complexity: O(n)   
    def monotonicstack(self, arr: List[int]) -> int:
        n = len(arr)
        s1 = []
        s2 = []
        left = [None]*n
        right = [None]*n
        
        for i in range(n):
            cnt = 1
            
            while len(s1) > 0 and s1[-1][0] > arr[i]:
                cnt += s1[-1][1]
                s1.pop()
            s1.append([arr[i],cnt])
            left[i] = cnt
            
        for i in range(n-1,-1,-1):
            cnt = 1
            
            while len(s2) > 0 and s2[-1][0] >= arr[i]:
                cnt += s2[-1][1]
                s2.pop()
            s2.append([arr[i],cnt])
            right[i] = cnt
            
        res = 0
        for i in range(n):
            res += (left[i]*right[i]*arr[i])%self.mod
        return res%self.mod
    
    # Time Complexity: O(n)
    # Space Complexity: O(n)   
    def dp(self, arr: List[int]) -> int:
        n = len(arr)
        dp = [0]*n
        
        st = []

        ans = 0
        
        for i in range(n-1,-1,-1):
            while st and arr[st[-1]] >= arr[i]:
                st.pop()
                
            if st:
                dp[i] = dp[st[-1]] + arr[i]*(st[-1]-i)

            else:
                dp[i] = arr[i]*(n-i)
                
            st.append(i)
            ans+=dp[i]%self.mod
        return ans%self.mod