leetcode - 907. Sum of Subarray Minimums

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 10^9 + 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 * 10^4
1 <= arr[i] <= 3 * 10^4

Solution

Solved after help…

The most straightforward way would be: find all the sub arrays, and sum the minimum value. But this way the time complexity would be o ( n 2 ) o(n^2) o(n2), which is not feasible for this question.

So I think about we could choose each element as the minimum, and expand to left and to right from the element. Until we find the smaller element, keep expanding.

To find the less element from left and from right, we could use monotonic stack.

After finding the less elements, let’s say, left_less and right_less keep the index for the first less element of the current element. Then the number of subarray is (n+1)*n//2, where n is the number of elements in between left_less[i] and right_less[i]. But we need to calculate the number of sub array that contains arr[i], so we could subtract the sub arrays that are at the left of i, and the sub arrays that are at the right of i.

  -1,0,1,2,3,4,5,6,7,8,9
	[2,3,5,7,9,4,7,8,4]
     |		   |	   |
left_less	cur_ele	right_less

As showed above, the number of elements should be 8, and the number of elements at the left should be 4, the number of elements at the right should be 3.

So the number of sub arrays that contains 4 is: 8 ∗ ( 8 + 1 ) / / 2 − 4 ∗ ( 4 + 1 ) / / 2 − 3 ∗ ( 3 + 1 ) / / 2 8*(8+1)//2-4*(4+1)//2-3*(3+1)//2 8(8+1)//24(4+1)//23(3+1)//2

But, there will be some duplicates, for example: arr=[71,55,82,55], then for the first 55, the subarray will contain [71,55,82,55], and for the second 55 it will also contain this subarray.

To deal with the duplicates, make left_less and right_less strictly less and non-strictly less respectively.

Time complexity: o ( n ) o(n) o(n)
Space complexity: o ( n ) o(n) o(n)

Code

class Solution:
    def sumSubarrayMins(self, arr: List[int]) -> int:
        left_less = []
        mono_stack = []
        for i in range(len(arr)):
            while mono_stack and arr[mono_stack[-1]] >= arr[i]:
                mono_stack.pop()
            if mono_stack:
                left_less.append(mono_stack[-1])
            else:
                left_less.append(-1)
            mono_stack.append(i)
        right_less = []
        mono_stack = []
        for i in range(len(arr) - 1, -1, -1):
            while mono_stack and arr[mono_stack[-1]] > arr[i]:
                mono_stack.pop()
            if mono_stack:
                right_less.append(mono_stack[-1])
            else:
                right_less.append(len(arr))
            mono_stack.append(i)
        right_less = right_less[::-1]
        res = 0
        mod_val = 1000000007
        whole_list = False
        for i in range(len(arr)):
            num_of_ele = right_less[i] - left_less[i] - 1
            num_of_ele_left = i - left_less[i] - 1
            num_of_ele_right = right_less[i] - i - 1
            num_of_subarr = (num_of_ele + 1) * num_of_ele // 2
            num_of_subarr_left = (num_of_ele_left + 1) * num_of_ele_left // 2
            num_of_subarr_right = (num_of_ele_right + 1) * num_of_ele_right // 2
            res += arr[i] * (num_of_subarr - num_of_subarr_left - num_of_subarr_right)
            res %= mod_val
        return res
  • 14
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值