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

43 阅读3分钟

问题分析

给定一个包含 𝑁 个元素的数组 𝑎,我们需要计算两个函数 𝐿(𝑖) 和 𝑅(𝑖),并最终求出 𝑀𝐴𝑋(𝑖)=𝐿(𝑖)×𝑅(𝑖) 的最大值。具体来说:

  • 𝐿(𝑖) 是满足 𝑗<𝑖 且 𝑎[𝑗]>𝑎[𝑖] 的最大的 𝑗 值。如果找不到这样的 𝑗,则 𝐿(𝑖)=0。
  • 𝑅(𝑖) 是满足 𝑘>𝑖 且 𝑎[𝑘]>𝑎[𝑖] 的最小的 𝑘 值。如果找不到这样的 𝑘,则 𝑅(𝑖)=0。

解决思路

  1. 单调栈:我们可以使用单调栈来高效地计算 𝐿(𝑖)L(i) 和 𝑅(𝑖)R(i)。
  2. 遍历数组:分别从左到右和从右到左遍历数组,使用单调栈来找到每个位置的 𝐿(𝑖)L(i) 和 𝑅(𝑖)R(i)。
  3. 计算 𝑀𝐴𝑋(𝑖) :最后遍历数组,计算每个位置的 𝑀𝐴𝑋(𝑖)MAX(i),并找出最大值。

详细步骤

1. 初始化

  • 创建数组:创建两个数组 L 和 R,分别用于存储 𝐿(𝑖) 和 𝑅(𝑖) 的值。初始值都设为 0。
  • 创建栈:创建两个栈 stack_L 和 stack_R,分别用于计算 𝐿(𝑖) 和 𝑅(𝑖)。

2. 计算 𝐿(𝑖)

  • 从左到右遍历数组:使用一个单调递减栈来找到每个位置的 𝐿(𝑖)。

    • 栈的使用:栈中存储的是数组的索引,栈顶元素对应的值大于当前元素时,更新 L 数组。

    • 具体步骤

      1. 初始化一个空栈 stack_L

      2. 遍历数组 a,对于每个元素 a[i]

        • 弹出栈顶元素:如果栈不为空且栈顶元素对应的值小于等于 a[i],则弹出栈顶元素。
        • 更新 L[i] :如果栈不为空,栈顶元素即为 𝐿(𝑖)L(i)。
        • 将当前索引入栈:将当前索引 i 压入栈中。

3. 计算 𝑅(𝑖)

  • 从右到左遍历数组:使用一个单调递减栈来找到每个位置的 𝑅(𝑖)。

    • 栈的使用:栈中存储的是数组的索引,栈顶元素对应的值大于当前元素时,更新 R 数组。

    • 具体步骤

      1. 初始化一个空栈 stack_R

      2. 逆序遍历数组 a,对于每个元素 a[i]

        • 弹出栈顶元素:如果栈不为空且栈顶元素对应的值小于等于 a[i],则弹出栈顶元素。
        • 更新 R[i] :如果栈不为空,栈顶元素即为 𝑅(𝑖)。
        • 将当前索引入栈:将当前索引 i 压入栈中。

4. 计算 𝑀𝐴𝑋(𝑖)

  • 遍历数组:遍历数组 a,计算每个位置的 𝑀𝐴𝑋(𝑖)=𝐿(𝑖)×𝑅(𝑖)。

    • 具体步骤

      1. 初始化一个变量 max_value 为 0。

      2. 遍历数组 a,对于每个元素 a[i]

        • 计算 𝑀𝐴𝑋(𝑖)MAX(i) :计算 L[i] * R[i]
        • 更新最大值:如果 L[i] * R[i] 大于 max_value,则更新 max_value

代码实现

def solution(n, array):
# 初始化 L 和 R 数组
L = [0] * n
R = [0] * n
# 使用栈来计算 L(i)
stack = []
for i in range(n):
    while stack and array[stack[-1]] <= array[i]:
        stack.pop()
    if stack:
        L[i] = stack[-1] + 1  # 因为题目要求的是索引值,而不是索引
    stack.append(i)

# 清空栈,计算 R(i)
stack = []
for i in range(n-1, -1, -1):
    while stack and array[stack[-1]] <= array[i]:
        stack.pop()
    if stack:
        R[i] = stack[-1] + 1  # 因为题目要求的是索引值,而不是索引
    stack.append(i)

# 计算 MAX(i) 并找到最大值
max_product = 0
for i in range(n):
    max_product = max(max_product, L[i] * R[i])

return max_product

if __name__ == "__main__":
# Add your test cases here
print(solution(5, [5, 4, 3, 4, 5]) == 8)
print(solution(6, [2, 1, 4, 3, 6, 5]) == 15)
print(solution(7, [1, 2, 3, 4, 5, 6, 7]) == 0)

通过这种方法,我们可以在 𝑂(𝑁)的时间复杂度内高效地解决这个问题。

总结

通过这道题目,我不仅巩固了对单调栈的理解,还学会了如何高效地处理数组问题,提高了代码的可读性和性能。单调栈是一种非常有效的数据结构,特别适用于解决涉及前后关系的问题。通过维护一个单调递增或递减的栈,可以快速找到某个元素的前一个或后一个满足特定条件的元素。在处理数组问题时,有时需要从两个方向遍历数组。从左到右和从右到左的遍历可以分别解决不同方向上的问题,如 𝐿(𝑖) 和 𝑅(𝑖) 的计算。这些经验和技巧在解决其他类似问题时也非常有用。