最大区间乘积问题 | 豆包MarsCode AI刷题

100 阅读2分钟

题目解析

问题描述

小R正在处理一个数组序列,他的任务是找出一个区间,使得这个区间的所有数经过以下计算得到的值是最大的:

区间中的最小数 * 区间所有数的和

小R想知道,经过计算后,哪个区间能产生最大的值。你的任务是帮助小R编写一个程序,输出最大计算值。

任务

  • 输出经过计算后,能产生最大值的区间对应的计算结果。

示例

  • 输入:n = 3, a = [6, 2, 1]

    • 区间 [6] = 6 * 6 = 36
    • 区间 [2] = 2 * 2 = 4
    • 区间 [1] = 1 * 1 = 1
    • 区间 [6, 2] = 2 * 8 = 16
    • 区间 [2, 1] = 1 * 3 = 3
    • 区间 [6, 2, 1] = 1 * 9 = 9
    • 最大值为 36
  • 输入:n = 4, a = [5, 1, 4, 3]

    • 最大值为 25(通过计算可以得到)
  • 输入:n = 5, a = [7, 3, 2, 1, 8]

    • 最大值为 64(通过计算可以得到)

解题思路

  1. 暴力解法

    • 遍历所有可能的区间,计算每个区间的最小值和总和,然后计算两者的乘积。
    • 时间复杂度:O(n^3)(外层两层循环遍历区间,内层循环找最小值)
    • 空间复杂度:O(1)
  2. 优化解法

    • 使用单调栈来优化查找每个区间的最小值。

      • 单调递增栈可以记录每个元素左边第一个比它小的元素的位置,右边同理。
      • 利用单调栈,可以在O(n)时间内预处理每个元素作为最小值时的区间范围。
    • 使用前缀和来快速计算任意区间的总和。

      • 前缀和数组可以在O(n)时间内预处理完成,之后可以在O(1)时间内计算任意区间的和。
    • 结合两者,可以在O(n)时间内找到结果。

具体实现步骤(暴力解法示例):

  1. 初始化最大值为负无穷。
  2. 使用两层嵌套循环遍历所有可能的区间。
  3. 在内层循环中,计算当前区间的最小值和总和。
  4. 计算当前区间的值(最小值 * 总和)。
  5. 更新最大值。
  6. 返回最大值。

代码示例(暴力解法):

def solution(n: int, a: list) -> int:
    max_value = float('-inf')
    for i in range(n):
        for j in range(i, n):
            min_value = min(a[i:j+1])
            sum_value = sum(a[i:j+1])
            current_value = min_value * sum_value
            if current_value > max_value:
                max_value = current_value
    return max_value
# 测试
if __name__ == '__main__':
    print(solution(n = 3, a = [6, 2, 1]) == 36)
    print(solution(n = 4, a = [5, 1, 4, 3]) == 25)
    print(solution(n = 5, a = [7, 3, 2, 1, 8]) == 64)

优化解法

  1. 使用单调栈预处理每个元素左边和右边第一个比它小的元素的位置。
  2. 使用前缀和数组快速计算区间和。
  3. 遍历数组,根据单调栈的结果计算每个元素作为最小值时的区间值,并更新最大值。