最大乘积问题做题笔记

93 阅读3分钟

题目描述

小R最近遇到了一个数组问题。他有一个包含 N 个元素的数组,记作 a1, a2, ..., aN

为了分析这个数组的特性,小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. 理解问题需求
  • 对于每一个元素 a[i],我们需要找出它左边第一个大于它的元素(即 L(i))以及右边第一个大于它的元素(即 R(i))。
  • 如果 L(i)R(i) 都存在,那么 MAX(i) = L(i) * R(i);否则,MAX(i) 为 0。
  • 最终,我们的目标是找到所有 MAX(i) 中的最大值。
2. 算法的实现步骤
  • 计算 L(i) :对于每个 i,我们可以通过从左到右扫描数组来找出左边第一个大于 a[i] 的元素。为了提高效率,可以使用一个栈来帮助快速查找。

    • 对于每个元素 a[i],从栈顶检查是否存在比 a[i] 大的元素。如果有,则更新 L(i),如果没有,则将 0 作为结果。
  • 计算 R(i) :与计算 L(i) 相似,但是这次我们是从右向左扫描数组,找出右边第一个大于 a[i] 的元素。

  • 最终结果:对于每个 i,计算 L(i) * R(i),更新最大值。

3. 时间复杂度分析
  • L(i)R(i) 的计算都涉及到栈的使用,栈的操作时间复杂度是 O(1),因此整个算法的时间复杂度是 O(N),其中 N 是数组的大小。

Java代码实现

import java.util.Stack;
public class Main {
    public static int solution(int n, int[] array) {
        // Edit your code here
        int[] L = new int[n];
        int[] R = new int[n];

        // 栈用于计算L(i)
        Stack<Integer> stackL = new Stack<>();
        // 从左到右计算L(i)
        for (int i = 0; i < n; i++) {
            while (!stackL.isEmpty() && array[stackL.peek()] <= array[i]) {
                stackL.pop();
            }
            L[i] = (stackL.isEmpty()) ? 0 : stackL.peek() + 1; 
            stackL.push(i);
        }

        // 栈用于计算R(i)
        Stack<Integer> stackR = new Stack<>();
        // 从右到左计算R(i)
        for (int i = n - 1; i >= 0; i--) {
            while (!stackR.isEmpty() && array[stackR.peek()] <= array[i]) {
                stackR.pop();
            }
            R[i] = (stackR.isEmpty()) ? 0 : stackR.peek() + 1; 
            stackR.push(i);
        }

        // 计算MAX(i)并找出最大值
        int maxProduct = 0;
        for (int i = 0; i < n; i++) {
            maxProduct = Math.max(maxProduct, L[i] * R[i]);
        }

        return maxProduct;
    }

    public static void main(String[] args) {
        // Add your test cases here

        System.out.println(solution(5, new int[]{5, 4, 3, 4, 5}) == 8);
    }
}

代码说明

  1. 输入和初始化

    • 输入一个数组 array,并定义两个数组 LR 来分别存储每个位置的 L(i)R(i) 值。
  2. 计算 L(i)

    • 使用一个栈 leftStack 来存储索引。遍历数组,对于每个元素 a[i],找到它左边第一个大于它的元素。
    • 如果栈顶的元素小于等于 a[i],则弹出栈顶元素,继续查找。
  3. 计算 R(i)

    • 使用类似的方法来计算右边第一个大于它的元素。这里的栈 rightStack 存储的是索引,从右到左遍历数组。
  4. 计算 MAX(i)

    • 对每个位置 i,计算 L(i) * R(i),并找出最大值。

总结

  • 本题的核心是如何高效计算每个位置 L(i)R(i),利用栈的特性能够在 O(N) 的时间复杂度内完成。
  • 通过两次栈的遍历(分别从左到右和从右到左),可以迅速找到每个元素左边和右边第一个大于它的元素,从而计算出 MAX(i)