问题分析
给定一个包含 𝑁 个元素的数组 𝑎,我们需要计算两个函数 𝐿(𝑖) 和 𝑅(𝑖),并最终求出 𝑀𝐴𝑋(𝑖)=𝐿(𝑖)×𝑅(𝑖) 的最大值。具体来说:
- 𝐿(𝑖) 是满足 𝑗<𝑖 且 𝑎[𝑗]>𝑎[𝑖] 的最大的 𝑗 值。如果找不到这样的 𝑗,则 𝐿(𝑖)=0。
- 𝑅(𝑖) 是满足 𝑘>𝑖 且 𝑎[𝑘]>𝑎[𝑖] 的最小的 𝑘 值。如果找不到这样的 𝑘,则 𝑅(𝑖)=0。
解决思路
- 单调栈:我们可以使用单调栈来高效地计算 𝐿(𝑖)L(i) 和 𝑅(𝑖)R(i)。
- 遍历数组:分别从左到右和从右到左遍历数组,使用单调栈来找到每个位置的 𝐿(𝑖)L(i) 和 𝑅(𝑖)R(i)。
- 计算 𝑀𝐴𝑋(𝑖) :最后遍历数组,计算每个位置的 𝑀𝐴𝑋(𝑖)MAX(i),并找出最大值。
详细步骤
1. 初始化
- 创建数组:创建两个数组
L和R,分别用于存储 𝐿(𝑖) 和 𝑅(𝑖) 的值。初始值都设为 0。 - 创建栈:创建两个栈
stack_L和stack_R,分别用于计算 𝐿(𝑖) 和 𝑅(𝑖)。
2. 计算 𝐿(𝑖)
-
从左到右遍历数组:使用一个单调递减栈来找到每个位置的 𝐿(𝑖)。
-
栈的使用:栈中存储的是数组的索引,栈顶元素对应的值大于当前元素时,更新
L数组。 -
具体步骤:
-
初始化一个空栈
stack_L。 -
遍历数组
a,对于每个元素a[i]:- 弹出栈顶元素:如果栈不为空且栈顶元素对应的值小于等于
a[i],则弹出栈顶元素。 - 更新
L[i]:如果栈不为空,栈顶元素即为 𝐿(𝑖)L(i)。 - 将当前索引入栈:将当前索引
i压入栈中。
- 弹出栈顶元素:如果栈不为空且栈顶元素对应的值小于等于
-
-
3. 计算 𝑅(𝑖)
-
从右到左遍历数组:使用一个单调递减栈来找到每个位置的 𝑅(𝑖)。
-
栈的使用:栈中存储的是数组的索引,栈顶元素对应的值大于当前元素时,更新
R数组。 -
具体步骤:
-
初始化一个空栈
stack_R。 -
逆序遍历数组
a,对于每个元素a[i]:- 弹出栈顶元素:如果栈不为空且栈顶元素对应的值小于等于
a[i],则弹出栈顶元素。 - 更新
R[i]:如果栈不为空,栈顶元素即为 𝑅(𝑖)。 - 将当前索引入栈:将当前索引
i压入栈中。
- 弹出栈顶元素:如果栈不为空且栈顶元素对应的值小于等于
-
-
4. 计算 𝑀𝐴𝑋(𝑖)
-
遍历数组:遍历数组
a,计算每个位置的 𝑀𝐴𝑋(𝑖)=𝐿(𝑖)×𝑅(𝑖)。-
具体步骤:
-
初始化一个变量
max_value为 0。 -
遍历数组
a,对于每个元素a[i]:- 计算 𝑀𝐴𝑋(𝑖)MAX(i) :计算
L[i] * R[i]。 - 更新最大值:如果
L[i] * R[i]大于max_value,则更新max_value。
- 计算 𝑀𝐴𝑋(𝑖)MAX(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 # 因为题目要求的是索引值,而不是索引
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)
通过这种方法,我们可以在 𝑂(𝑁)的时间复杂度内高效地解决这个问题。
总结
通过这道题目,我不仅巩固了对单调栈的理解,还学会了如何高效地处理数组问题,提高了代码的可读性和性能。单调栈是一种非常有效的数据结构,特别适用于解决涉及前后关系的问题。通过维护一个单调递增或递减的栈,可以快速找到某个元素的前一个或后一个满足特定条件的元素。在处理数组问题时,有时需要从两个方向遍历数组。从左到右和从右到左的遍历可以分别解决不同方向上的问题,如 𝐿(𝑖) 和 𝑅(𝑖) 的计算。这些经验和技巧在解决其他类似问题时也非常有用。