最大乘积问题
一、问题重现
问题描述
对于一个有 N 个元素的数组,包含如下的元素 a1, a2, ..., an,我们定义了两个函数:
-
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),我们需要找到 MAX(i) 的最大值,其中 1 <= i <= N。
输入格式
总共有两行,第一行是数组长度 N,第二个是空格分割的所有数组的内容。
输出格式
输出 MAX(i) 的最大值。
输入样例
5
5 4 3 4 5
输出样例
8
解释说明
- L(1) = 0,所以 MAX(1) = 0
- L(2) = 1, R(2) = 5,所以 MAX(2) = 1 * 5 = 5
- L(3) = 2, R(3) = 4,所以 MAX(3) = 2 * 4 = 8
- L(4) = 1, R(4) = 5,所以 MAX(4) = 1 * 5 = 5
- R(5) = 0,所以 MAX(5) = 0
数据范围
- 1<=N<=1051<=N<=105
- 1<=a[i]<=1091<=a[i]<=109
二、解题思路
问题理解
我们需要找到数组中每个元素的 L(i) 和 R(i),然后计算 MAX(i) = L(i) * R(i),并找出 MAX(i) 的最大值。
L(i)是小于i且大于a[i]的最近元素的索引。R(i)是大于i且大于a[i]的最近元素的索引。
数据结构选择
由于我们需要频繁地查找和更新 L(i) 和 R(i),而这里寻找 L(i) 和 R(i)的过程是单调对比的,所以并不需要记录每一层的 L(i) 和 R(i),保持最大值即可。
算法步骤
-
初始化:
- 定义一个变量
ans用于存储MAX(i)的最大值,初始值为0。
- 定义一个变量
-
遍历数组:
- 使用外层循环遍历数组中的每个元素
a[i]。
- 使用外层循环遍历数组中的每个元素
-
计算
L(i):- 对于每个元素
a[i],使用内层循环从i-1开始向左遍历,找到第一个大于a[i]的元素a[j],并记录其索引j + 1作为L。
- 对于每个元素
-
计算
R(i):- 对于每个元素
a[i],使用内层循环从i+1开始向右遍历,找到第一个大于a[i]的元素a[k],并记录其索引k + 1作为R。
- 对于每个元素
-
更新
ans:- 计算
L * R,并与当前的ans进行比较,更新ans为较大的值。
- 计算
-
返回结果:
- 遍历结束后,返回
ans作为最终结果。
- 遍历结束后,返回
三、代码实现
int solution(int n, std::vector<int> array) {
int ans = 0;
for(int i = 0; i < n; ++i) {
int L = 0, R = 0;
for(int j = i-1; j >= 0; --j) {
if(array[j] > array[i]){
L = j + 1;
break;
}
}
for(int k = i + 1; k < n; ++k) {
if(array[k] > array[i]){
R = k + 1;
break;
}
}
ans = L * R > ans ? L * R : ans;
}
return ans;
}
四、算法复杂度分析
-
时间复杂度:
- 外层循环遍历数组的时间复杂度为
O(N)。 - 内层循环分别向左和向右查找
L(i)和R(i),最坏情况下每个内层循环的时间复杂度为O(N)。 - 因此,总的时间复杂度为
O(N^2)。
- 外层循环遍历数组的时间复杂度为
-
空间复杂度:
- 只使用了常数级别的额外空间,空间复杂度为
O(1)。
- 只使用了常数级别的额外空间,空间复杂度为