LeetCode 题解工作台

子数组最小乘积的最大值

一个数组的 最小乘积 定义为这个数组中 最小值 乘以 数组的 和 。 比方说,数组 [3,2,5] (最小值是 2 )的最小乘积为 2 * (3+2+5) = 2 * 10 = 20 。 给你一个正整数数组 nums ,请你返回 nums 任意 非空子数组 的 最小乘积 的 最大值 。由于答案可能很…

category

4

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

中等 · 栈·状态

bolt

答案摘要

我们可以枚举每个元素 作为子数组的最小值,找出子数组的左右边界 和 。其中 表示 左侧第一个严格小于 的位置,而 表示 右侧第一个小于等于 的位置。 为了方便地算出子数组的和,我们可以预处理出前缀和数组 ,其中 表示 前 个元素的和。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 栈·状态 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

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

  • 比方说,数组 [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
lightbulb

解题思路

方法一:单调栈 + 前缀和

我们可以枚举每个元素 nums[i]nums[i] 作为子数组的最小值,找出子数组的左右边界 left[i]left[i]right[i]right[i]。其中 left[i]left[i] 表示 ii 左侧第一个严格小于 nums[i]nums[i] 的位置,而 right[i]right[i] 表示 ii 右侧第一个小于等于 nums[i]nums[i] 的位置。

为了方便地算出子数组的和,我们可以预处理出前缀和数组 ss,其中 s[i]s[i] 表示 numsnumsii 个元素的和。

那么以 nums[i]nums[i] 作为子数组最小值的最小乘积为 nums[i]×s[right[i]]s[left[i]+1]nums[i] \times s[right[i]] - s[left[i] + 1]。我们可以枚举每个元素 nums[i]nums[i],求出以 nums[i]nums[i] 作为子数组最小值的最小乘积,然后取最大值即可。

时间复杂度 O(n)O(n),空间复杂度 O(n)O(n)。其中 nn 为数组 numsnums 的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution:
    def maxSumMinProduct(self, nums: List[int]) -> int:
        n = len(nums)
        left = [-1] * n
        right = [n] * n
        stk = []
        for i, x in enumerate(nums):
            while stk and nums[stk[-1]] >= x:
                stk.pop()
            if stk:
                left[i] = stk[-1]
            stk.append(i)
        stk = []
        for i in range(n - 1, -1, -1):
            while stk and nums[stk[-1]] > nums[i]:
                stk.pop()
            if stk:
                right[i] = stk[-1]
            stk.append(i)
        s = list(accumulate(nums, initial=0))
        mod = 10**9 + 7
        return max((s[right[i]] - s[left[i] + 1]) * x for i, x in enumerate(nums)) % mod
speed

复杂度分析

指标
时间Depends on the final approach
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Assess if the candidate can optimize subarray operations using stacks.

  • question_mark

    Look for the candidate's ability to balance time complexity with large input sizes.

  • question_mark

    Test understanding of maximizing values before applying modulo operations.

warning

常见陷阱

外企场景
  • error

    Forgetting to calculate the subarray sum efficiently using prefix sums.

  • error

    Applying modulo too early, which can lead to suboptimal results.

  • error

    Failing to correctly manage the stack to ensure minimum values are properly tracked.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Consider variations where negative numbers are allowed in the array.

  • arrow_right_alt

    What if you had to compute the result for multiple subarrays at once?

  • arrow_right_alt

    What changes if the array size is fixed or if a specific range of subarrays needs to be considered?

help

常见问题

外企场景

子数组最小乘积的最大值题解:栈·状态 | LeetCode #1856 中等