最大乘积问题
对于一个有 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
问题分析
最大乘积问题,
涉及到计算数组中每个元素 a[i]
的左右关系,通过找到左边和右边大于 a[i]
的最近元素,并计算它们下标索引的乘积。
每个元素 a[i]
的最大乘积 MAX(i) = L(i) * R(i)
,
L(i)
是离 a[i]
最近且值大于 a[i]
的元素在其左边的索引(如果不存在,则为 0)。
R(i)
是离 a[i]
最近且值大于 a[i]
的元素在其右边的索引(如果不存在,则为 0)。
目标是求出 MAX(i)
的最大值。
step1:计算 L(i)
:
L(i)
是从数组的左边开始扫描,找到第一个大于 a[i]
的元素。使用栈辅助
- 1.遍历数组,遇到一个元素,用stack存储元素的下标索引。
- 2.如果栈顶元素stack.top<=当前元素,则弹出栈顶,直到栈顶元素stack.top>当前元素为止。
- 3.如果栈顶元素存在,则说明它是离当前元素最近的左侧大于当前元素的元素。
- 4.将该下标记录为
L(i)
,并将当前下标压入栈中。
step2:计算 R(i)
: R(i)
的计算与 L(i)
类似,只不过是从右到左遍历数组。使用栈,直到找到右边第一个大于当前元素的元素。
step3:计算 MAX(i)
: 对于每个元素 i
,计算 MAX(i) = L(i) * R(i)
,并记录最大的值。
复杂度计算:
由于栈的操作时间复杂度是 O(1),因此对每个元素计算 L(i)
和 R(i)
的过程时间复杂度为 O(N),总体时间复杂度为 O(N)。
- 计算
L(i)
:
初始化一个空栈 left_stack
。遍历数组,对于每个元素:
如果栈不为空(!left_stack.empty()
)且栈顶元素小于等于当前元素( array[left_stack.top()] <= array[i]
),则弹出栈顶元素。
如果栈不为空,说明栈顶元素是离当前元素最近的比当前元素大的元素,更新 L(i)
。
将当前元素的索引压入栈。
- 计算
R(i)
:
初始化一个空栈 right_stack
。反向遍历数组,对于每个元素:
如果栈不为空(!right_stack.empty()
)且栈顶元素小于等于当前元素( array[right_stack.top()] <= array[i]
),则弹出栈顶元素。
如果栈不为空,说明栈顶元素是离当前元素最近的比当前元素大的元素,更新 R(i)
。
将当前元素的索引压入栈。
- 计算最大乘积:
对于每个元素 i
,计算 L(i) * R(i)
,并找到最大值。
代码如下
#include <iostream>
#include <vector>
#include <stack>
int solution(int n, std::vector<int> array) {
std::vector<int> L(n, 0); //初始化L(i)
std::vector<int> R(n, 0); //初始化R(i)
//计算 L(i)
std::stack<int> left_stack; // 用栈来计算 L(i)
for (int i = 0; i < n; ++i) {
while (!left_stack.empty() && array[left_stack.top()] <= array[i]) {
left_stack.pop();
}
if (!left_stack.empty()) {
L[i] = left_stack.top() + 1; //+1是题目中索引从1开始
}
left_stack.push(i);
}
// 计算 R(i)
std::stack<int> right_stack; // 用栈来计算 R(i)
for (int i = n - 1; i >= 0; --i) {
while (!right_stack.empty() && array[right_stack.top()] <= array[i]) {
right_stack.pop();
}
if (!right_stack.empty()) {
R[i] = right_stack.top() + 1; //+1是题目中索引从1开始
}
right_stack.push(i);
}
int max_value = 0;
for (int i = 0; i < n; ++i) {
int max_i = L[i] * R[i];
max_value = std::max(max_value, max_i);
}
return max_value;
}
int main() {
std::cout << (solution(5, {5, 4, 3, 4, 5}) == 8) << std::endl;
return 0;
}