907-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