原题地址907. 子数组的最小值之和
给定一个整数数组 A
,找到 min(B)
的总和,其中 B
的范围为 A
的每个(连续)子数组。
由于答案可能很大,因此返回答案模 10^9 + 7
。
示例:
输入:[3,1,2,4]
输出:17
解释:
子数组为 [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。
最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。
提示:
1 <= A <= 30000
1 <= A[i] <= 30000
算法
归纳法可以直到每个元素 A[i] 被加入到最终结果的次数为其左邻居中大于它、右邻居中不小于它的元素长度 left 、 right (包括自身)的乘积。
示例:[3,1,2,4]
元素 | left | right |
---|---|---|
3 | 1 | 1 |
1 | 2 | 3 |
2 | 1 | 2 |
4 | 1 | 1 |
上边每一行相乘的结果累加得到结果17
因此原问题转换成寻找每个元素的 left 和 right 值。逐个判断,会超时。因此使用数组记录左侧元素的 left 值和右侧元素的 right 值。
对当前元素 A[i] ,如果 A[i]>=A[i-1] ,那么 left[i]=1 ;反之,A[i]<A[i-1] 可以推得 A[i]<A[i-left[i-1]] 。
另一侧同理。
代码
def fun(A):
"""
:type A: List[int]
:rtype: int
"""
ans = 0
maxindex = len(A) - 1
left = []
right = []
for i in range(0, maxindex + 1):
numleft = 1
while i - numleft >= 0 and A[i - numleft] > A[i]:
numleft += left[i - numleft]
left.append(numleft)
numright = 1
while maxindex - i + numright <= maxindex and A[maxindex - i + numright] >= A[maxindex - i]:
numright += right[i - numright]
right.append(numright)
for i in range(0, maxindex + 1):
ans += left[i] * right[maxindex - i] * A[i]
return ans % 1000000007