问题描述
小R最近遇到了一个数组问题。他有一个包含 N 个元素的数组,记作 a1,a2,...,aN。为了分析这个数组的特性,小R定义了两个函数 L(i) 和 )R(i),并希望通过这两个函数来找到一些有趣的结论。
- L(i) 是满足以下条件的最大的 j 值:
- j<i
- a[j]>a[i]
- 如果找不到这样的 j,那么 L(i)=0;如果有多个满足条件的 j,选择离 i 最近的那个。
- R(i) 是满足以下条件的最小的 k 值:
- k>i
- a[k]>a[i]
- 如果找不到这样的 k,那么 R(i)=0;如果有多个满足条件的 k,选择离 i 最近的那个。 最终,小定义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
思路分析
1. 初始化
left和right数组分别用于存储每个元素左边和右边第一个比当前元素小的元素的索引。- 使用栈
stack来辅助计算left和right数组。
2. 计算 left 数组
- 遍历数组,从左到右。
- 对于每个元素
array[i],使用栈来维护一个递增序列。 - 如果栈顶元素对应的值小于等于当前元素,则弹出栈顶元素,直到栈为空或者栈顶元素对应的值大于当前元素。
- 如果栈不为空,则
left[i]就是栈顶元素的索引加1;否则,left[i]为0。 - 将当前索引
i压入栈中。
3. 计算 right 数组
- 遍历数组,从右到左。
- 方法与计算
left数组类似,只是方向相反。 - 如果栈顶元素对应的值小于等于当前元素,则弹出栈顶元素,直到栈为空或者栈顶元素对应的值大于当前元素。
- 如果栈不为空,则
right[i]就是栈顶元素的索引加1;否则,right[i]为0。 - 将当前索引
i压入栈中。
4. 计算结果
- 遍历数组,计算每个元素的
left[i] * right[i],并更新最大值。
代码详解
时间复杂度为 O(n)
涉及到的知识点
1. 数据结构
- 栈(Stack) :栈是一种后进先出(LIFO)的数据结构,用于辅助计算
left和right数组。 - 数组(Array) :用于存储输入数据和中间结果。
2. 算法设计
- 单调栈(Monotonic Stack) :栈内元素保持单调性(递增或递减),用于高效地找到左右边界。
- 动态规划(Dynamic Programming) :虽然这里没有显式的动态规划实现,但利用栈来计算
left和right数组的过程类似于动态规划的思想。
3. 数组操作
- 填充数组(Array Filling) :使用
Array.fill(0)初始化left和right数组。 - 遍历数组(Array Traversal) :从左到右和从右到左遍历数组,分别计算
left和right数组。
4. 数学计算
- 矩形面积计算:根据
left和right数组计算每个元素的矩形面积,并找到最大值。
总结
通过青训营豆包MarsCode AI刷题,我能够更好地理解和应用单调栈、数组操作等知识。并且青训营的学习不仅提升了我的技术能力,还培养了我的问题分析和解决能力,希望我能学到更多的知识,提升自己。