题目解析(五)| 豆包MarsCode AI刷题

87 阅读4分钟

题目解析

题目描述
小R最近遇到了一个数组问题。他有一个包含 N 个元素的数组 a[1], a[2], ..., a[N]。为了分析这个数组的特性,小R定义了两个函数 L(i)R(i),并希望通过这两个函数来找到一些有趣的结论。

  1. L(i) 是满足以下条件的最大的 j 值:

    • j < i
    • a[j] > a[i]

    如果找不到这样的 j,则 L(i) = 0。如果有多个满足条件的 j,选择离 i 最近的那个。

  2. R(i) 是满足以下条件的最小的 k 值:

    • k > i
    • a[k] > a[i]

    如果找不到这样的 k,则 R(i) = 0。如果有多个满足条件的 k,选择离 i 最近的那个。

最终,小R定义了 MAX(i) = L(i) * R(i),他想知道在 1 ≤ i ≤ N 的范围内,MAX(i) 的最大值是多少。

image.png

示例

示例1
输入:
n = 5, array = [5, 4, 3, 4, 5]
输出:
8

示例2
输入:
n = 6, array = [2, 1, 4, 3, 6, 5]
输出:
15

示例3
输入:
n = 7, array = [1, 2, 3, 4, 5, 6, 7]
输出:
0

思路分析

我们需要计算每个位置的 L(i)R(i) 值,然后计算 MAX(i) = L(i) * R(i),并找出所有 MAX(i) 中的最大值。

计算 L(i)

  • L(i) 是寻找在 i 前面的第一个比 a[i] 大的元素的索引。可以通过单调栈来实现。
  • 我们使用一个栈,从左到右扫描数组,维护一个递减栈。栈中存储的是数组元素的索引,当遇到当前元素时,我们会依次弹出栈中的索引,直到栈顶元素大于当前元素。

计算 R(i)

  • R(i) 是寻找在 i 后面的第一个比 a[i] 大的元素的索引。可以通过单调栈来实现。
  • 我们使用一个栈,从右到左扫描数组,维护一个递减栈。栈中存储的是数组元素的索引,当遇到当前元素时,我们会依次弹出栈中的索引,直到栈顶元素大于当前元素。

计算最大值

  • 遍历 L(i)R(i) 数组,计算 L(i) * R(i),并记录最大值。

代码实现

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  # 索引从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  # 索引从1开始
        stack.append(i)

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

    return max_value

代码说明

  1. L(i) 计算
    使用单调栈从左到右遍历数组。栈中存储的是元素的索引,栈保持递减顺序。当遇到一个元素时,栈顶的元素就是第一个大于该元素的索引,从而得到 L(i)
  2. R(i) 计算
    使用单调栈从右到左遍历数组。与计算 L(i) 类似,栈保持递减顺序,栈顶元素就是第一个大于当前元素的索引,从而得到 R(i)
  3. 计算最大值
    遍历 L(i)R(i) 数组,计算 L(i) * R(i) 并找出最大值。

时间复杂度

  • 时间复杂度O(n)。每一张卡牌的 L(i)R(i) 的计算都使用单调栈,因此每张卡牌仅会入栈和出栈一次,时间复杂度为 O(n)
  • 空间复杂度O(n),我们使用了两个数组 LR,每个数组的长度都是 n

边界情况

  1. 数组为空:如果 n = 0,则返回 0
  2. 所有元素相同:如果数组中所有元素都相同,L(i)R(i) 都为 0,则 MAX(i) 的最大值为 0
  3. 数组是递增的:如果数组是递增的,则 L(i) = 0R(i)i+1,最终的最大值为 0
  4. 数组是递减的:如果数组是递减的,则 L(i)iR(i) = 0,最终的最大值为 0

示例分析

示例1
输入:
n = 5, array = [5, 4, 3, 4, 5]

输出:
8
解释:对于 i = 4L(4) = 3R(4) = 5,因此 MAX(4) = 3 * 5 = 15,但是最终的最大值为 8

示例2
输入:
n = 6, array = [2, 1, 4, 3, 6, 5]

输出:
15

示例3
输入:
n = 7, array = [1, 2, 3, 4, 5, 6, 7]

输出:
0
解释:因为数组是递增的,所以没有符合条件的 L(i)R(i)

通过单调栈的巧妙运用,这个问题能在 O(n) 时间复杂度内高效求解。