The min-product of an array is equal to the minimum value in the array multiplied by the array's sum.
- For example, the array
[3,2,5]
(minimum value is2
) has a min-product of2 * (3+2+5) = 2 * 10 = 20
.
Given an array of integers nums
, return the maximum min-product of any non-empty subarray of nums
. Since the answer may be large, return it modulo 109 + 7
.
Note that the min-product should be maximized before performing the modulo operation. Testcases are generated such that the maximum min-product without modulo will fit in a 64-bit signed integer.
A subarray is a contiguous part of an array.
Example 1:
Input: nums = [1,2,3,2] Output: 14 Explanation: The maximum min-product is achieved with the subarray [2,3,2] (minimum value is 2). 2 * (2+3+2) = 2 * 7 = 14.
Example 2:
Input: nums = [2,3,3,1,2] Output: 18 Explanation: The maximum min-product is achieved with the subarray [3,3] (minimum value is 3). 3 * (3+3) = 3 * 6 = 18.
Example 3:
Input: nums = [3,1,5,6,4,2] Output: 60 Explanation: The maximum min-product is achieved with the subarray [5,6,4] (minimum value is 4). 4 * (5+6+4) = 4 * 15 = 60.
Constraints:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^7
题目对数组的最小积做了定义,即数组中的最小值与数组和的乘积。现在给定一个数组,要求从所有子数组找出具有最大的最小积的那个,返回最大的最小积。
暴力解法当然是计算每个子数组的最小积,从中找出最大的那个。所有子数组的问题都可以用暴力解法,但所有的子数组问题也都有更优解。
子数组的最小积是由子数组和与最小值决定的,数组中的所有子数组的最小值肯定是数组的某一个数,因此本题也就等价于以数组中每一个数为最小值的所有子数组的最小积。由于本题要找的是最大的最小积,在以某一个数为最小值的所有子数组中,当然最大的最小积就是以该数为最小值的最长的那个子数组,最长的子数组就是以该数为中心向左到第一个小于该数的位置(或数组开头),向右到第一个小于该数的位置(或数组结尾),两个位置之间的和与该数的乘积就是以该数为最小值的所有子数组中的最大的最小积。到此本题就变成了找每个数的向左的下一个更小数的位置和向右的下一个更小数。算法实现可参考单调栈(Monotonic Stack)系列题。
另外为了快速算出两个位置之间的和,可以用前缀和的算法。
class Solution:
def maxSumMinProduct(self, nums: List[int]) -> int:
n = len(nums)
preSum = [0] * (n + 1)
left = [-1] * n
st = []
for i in range(0, n):
preSum[i + 1] = preSum[i] + nums[i]
while st and nums[i] <= nums[st[-1]]:
st.pop()
left[i] = st[-1] if st else -1
st.append(i)
st = []
right = [n] * n
for i in range(n - 1, -1, -1):
while st and nums[i] <= nums[st[-1]]:
st.pop()
right[i] = st[-1] if st else n
st.append(i)
res = 0
for i in range(n):
res = max(res, nums[i] * (preSum[right[i]] - preSum[left[i] + 1]))
return res % (10 ** 9 + 7)