青训营X豆包MarsCode 技术训练营 字节青训营笔记3| 豆包MarsCode AI刷题

13 阅读4分钟

最大乘积问题

对于一个有 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. 1.遍历数组,遇到一个元素,用stack存储元素的下标索引。
  1. 2.如果栈顶元素stack.top<=当前元素,则弹出栈顶,直到栈顶元素stack.top>当前元素为止。
  1. 3.如果栈顶元素存在,则说明它是离当前元素最近的左侧大于当前元素的元素。
  1. 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)。

  1. 计算 L(i)

初始化一个空栈 left_stack。遍历数组,对于每个元素:

如果栈不为空(!left_stack.empty())且栈顶元素小于等于当前元素( array[left_stack.top()] <= array[i]),则弹出栈顶元素。

如果栈不为空,说明栈顶元素是离当前元素最近的比当前元素大的元素,更新 L(i)

将当前元素的索引压入栈。

  1. 计算 R(i)

初始化一个空栈 right_stack。反向遍历数组,对于每个元素:

如果栈不为空(!right_stack.empty())且栈顶元素小于等于当前元素( array[right_stack.top()] <= array[i]),则弹出栈顶元素。

如果栈不为空,说明栈顶元素是离当前元素最近的比当前元素大的元素,更新 R(i)

将当前元素的索引压入栈。

  1. 计算最大乘积:

对于每个元素 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;
}