LeetCode 1856. Maximum Subarray Min-Product - 亚马逊高频题30

给定一个整数数组,找到具有最大最小乘积的非空子数组。利用单调栈求解,通过找到每个数的左侧和右侧下一个较小的数,计算子数组和,最终找到最大乘积。问题转化为求解每个数对应的最长增序列两端的元素,结合前缀和加速计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.

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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值