题目解析
题目描述
小R最近遇到了一个数组问题。他有一个包含 N 个元素的数组 a[1], a[2], ..., a[N]。为了分析这个数组的特性,小R定义了两个函数 L(i) 和 R(i),并希望通过这两个函数来找到一些有趣的结论。
-
L(i) 是满足以下条件的最大的
j值:j < ia[j] > a[i]
如果找不到这样的
j,则L(i) = 0。如果有多个满足条件的j,选择离i最近的那个。 -
R(i) 是满足以下条件的最小的
k值:k > ia[k] > a[i]
如果找不到这样的
k,则R(i) = 0。如果有多个满足条件的k,选择离i最近的那个。
最终,小R定义了 MAX(i) = L(i) * R(i),他想知道在 1 ≤ i ≤ N 的范围内,MAX(i) 的最大值是多少。
示例
示例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
代码说明
- L(i) 计算:
使用单调栈从左到右遍历数组。栈中存储的是元素的索引,栈保持递减顺序。当遇到一个元素时,栈顶的元素就是第一个大于该元素的索引,从而得到L(i)。 - R(i) 计算:
使用单调栈从右到左遍历数组。与计算L(i)类似,栈保持递减顺序,栈顶元素就是第一个大于当前元素的索引,从而得到R(i)。 - 计算最大值:
遍历L(i)和R(i)数组,计算L(i) * R(i)并找出最大值。
时间复杂度
- 时间复杂度:
O(n)。每一张卡牌的L(i)和R(i)的计算都使用单调栈,因此每张卡牌仅会入栈和出栈一次,时间复杂度为O(n)。 - 空间复杂度:
O(n),我们使用了两个数组L和R,每个数组的长度都是n。
边界情况
- 数组为空:如果
n = 0,则返回0。 - 所有元素相同:如果数组中所有元素都相同,
L(i)和R(i)都为0,则MAX(i)的最大值为0。 - 数组是递增的:如果数组是递增的,则
L(i) = 0,R(i)为i+1,最终的最大值为0。 - 数组是递减的:如果数组是递减的,则
L(i)为i,R(i) = 0,最终的最大值为0。
示例分析
示例1
输入:
n = 5, array = [5, 4, 3, 4, 5]
输出:
8
解释:对于 i = 4,L(4) = 3,R(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) 时间复杂度内高效求解。