加载中...
1856-子数组最小乘积的最大值(Maximum Subarray Min-Product)
发表于:2021-12-03 | 分类: 中等
字数统计: 566 | 阅读时长: 2分钟 | 阅读量:

原文链接: https://leetcode-cn.com/problems/maximum-subarray-min-product

英文原文

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 is 2) has a min-product of 2 * (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 <= 105
  • 1 <= nums[i] <= 107

中文题目

一个数组的 最小乘积 定义为这个数组中 最小值 乘以 数组的  。

  • 比方说,数组 [3,2,5] (最小值是 2)的最小乘积为 2 * (3+2+5) = 2 * 10 = 20 。

给你一个正整数数组 nums ,请你返回 nums 任意 非空子数组 的最小乘积 的 最大值 。由于答案可能很大,请你返回答案对  109 + 7 取余 的结果。

请注意,最小乘积的最大值考虑的是取余操作 之前 的结果。题目保证最小乘积的最大值在 不取余 的情况下可以用 64 位有符号整数 保存。

子数组 定义为一个数组的 连续 部分。

 

示例 1:

输入:nums = [1,2,3,2]
输出:14
解释:最小乘积的最大值由子数组 [2,3,2] (最小值是 2)得到。
2 * (2+3+2) = 2 * 7 = 14 。

示例 2:

输入:nums = [2,3,3,1,2]
输出:18
解释:最小乘积的最大值由子数组 [3,3] (最小值是 3)得到。
3 * (3+3) = 3 * 6 = 18 。

示例 3:

输入:nums = [3,1,5,6,4,2]
输出:60
解释:最小乘积的最大值由子数组 [5,6,4] (最小值是 4)得到。
4 * (5+6+4) = 4 * 15 = 60 。

 

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 107

通过代码

高赞题解

思路:

我们可以考虑枚举数组中每个值n,并且以n作为子数组中的最小值,再乘以这个子数组的和,通过打擂台的方式得到最终答案。于是问题变成,

给定n,如何找到以n为最小值的子数组边界?

朴素的想法是维护左右指针不断扩大范围,但是这种做法总的时间复杂度是O(n^2),会超时,我们需要寻找一种更快的方法。问题可以继续转化成,

对于数组中的每一个元素,分别找到左边、右边第一个比它小的元素的位置

单调栈刚好可以帮助我们在O(n)的时间内完成。维护两个单调递增栈分别找到左右下一个更小的元素位置。再结合前缀和,最后总的时间复杂度为O(n)

代码

[]
class Solution: def maxSumMinProduct(self, nums: List[int]) -> int: # 左右添加两个哨兵,方便单调栈内的判断 nums = [0] + nums + [0] # 前缀和 presum = [0] for n in nums: presum.append(presum[-1] + n) # 右边第一个比它小的元素下标 right_first_smaller = [None] * len(nums) stack = [] for i in range(len(nums)): # 如果当前元素比栈顶元素小,弹栈 while stack and nums[i] < nums[stack[-1]]: right_first_smaller[stack.pop()] = i stack.append(i) # 左边第一个比它小的元素下标 left_first_smaller = [None] * len(nums) stack = [] for i in range(len(nums)-1,-1,-1): # 如果当前元素比栈顶元素小,弹栈 while stack and nums[i] < nums[stack[-1]]: left_first_smaller[stack.pop()] = i stack.append(i) # 打擂台得到答案 res = 0 for i in range(1,len(nums)-1): left = left_first_smaller[i] right = right_first_smaller[i] res = max(res, nums[i] * (presum[right] - presum[left+1])) return res % (10 ** 9 + 7)
[]
class Solution { public: int maxSumMinProduct(vector<int>& nums) { // 左右添加两个哨兵,方便单调栈内的判断 nums.insert(nums.begin(), 0); nums.push_back(0); // 前缀和 vector<long long> presum = {0}; for(auto& n: nums) presum.push_back(presum.back() + n); // 右边第一个比它小的元素下标 stack<int> s; vector<int> rightFirstSmaller(nums.size(), 0); for(int i = 0;i < nums.size();i++){ // 如果当前元素比栈顶元素小,弹栈 while(!s.empty() && nums[i] < nums[s.top()]){ int index = s.top(); s.pop(); rightFirstSmaller[index] = i; } s.push(i); } // 左边第一个比它小的元素下标 s = stack<int>(); vector<int> leftFirstSmaller(nums.size(), 0); for(int i = nums.size()-1;i >= 0;i--){ // 如果当前元素比栈顶元素小,弹栈 while(!s.empty() && nums[i] < nums[s.top()]){ int index = s.top(); s.pop(); leftFirstSmaller[index] = i; } s.push(i); } // 打擂台得到答案 long long res = 0; for(int i = 1;i < nums.size()-1;i++){ int l = leftFirstSmaller[i]; int r = rightFirstSmaller[i]; res = max(res,nums[i] * (presum[r] - presum[l+1])); } return res % 1000000007; } };

有关单调栈的入门题目:

必会高频题,重点掌握:

统计信息

通过次数 提交次数 AC比率
4704 13199 35.6%

提交历史

提交时间 提交结果 执行时间 内存消耗 语言
上一篇:
1855-下标对中的最大距离(Maximum Distance Between a Pair of Values)
下一篇:
1857-有向图中最大颜色值(Largest Color Value in a Directed Graph)
本文目录
本文目录