最大乘积问题

44 阅读3分钟

问题描述

小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 最近的那个。

最终,小R定义 MAX(i) = L(i) * R(i),他想知道在 1 ≤ i ≤ N 的范围内,MAX(i) 的最大值是多少。

解决方案

这个问题可以利用栈数据结构来高效解决。栈在处理这种需要快速查找最近的满足某种条件的元素的问题上非常有效。

步骤解析

  1. 计算 L(i)

    • 使用一个栈来维护左侧元素的索引。我们从左到右遍历数组,对于每个元素 a[i],在栈中找到左侧最近的大于 a[i] 的元素。
    • 如果找不到这样的元素,将 L(i) 设为 0。
  2. 计算 R(i)

    • 使用一个栈来维护右侧元素的索引。我们从右到左遍历数组,对于每个元素 a[i],在栈中找到右侧最近的大于 a[i] 的元素。
    • 如果找不到这样的元素,将 R(i) 设为 0。
  3. 计算 MAX(i)

    • 对于每个元素 a[i],计算 MAX(i) = L(i) * R(i) 并找出其中的最大值。

代码实现

以下是完整的Java代码实现,涵盖了以上步骤:

java

import java.util.Stack;

public class MaxProduct {
    public static void main(String[] args) {
        int[] array = {3, 1, 5, 6, 2, 7, 8, 4};
        System.out.println("最大值: " + getMaxProduct(array));
    }

    public static int getMaxProduct(int[] array) {
        int n = array.length;
        int[] L = new int[n];
        int[] R = new int[n];
        Stack<Integer> stack = new Stack<>();

        // 计算 L(i)
        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && array[stack.peek()] <= array[i]) {
                stack.pop();
            }
            L[i] = stack.isEmpty() ? 0 : stack.peek() + 1;
            stack.push(i);
        }

        stack.clear();

        // 计算 R(i)
        for (int i = n - 1; i >= 0; i--) {
            while (!stack.isEmpty() && array[stack.peek()] <= array[i]) {
                stack.pop();
            }
            R[i] = stack.isEmpty() ? 0 : stack.peek() + 1;
            stack.push(i);
        }

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

        return maxProduct;
    }
}

代码解释

  1. 计算 L(i)

    • 使用一个栈来维护左侧元素的索引。对于每个元素 a[i],我们在栈中找到左侧最近的大于 a[i] 的元素。
    • 如果栈为空,说明左侧没有大于 a[i] 的元素,将 L[i] 设为 0。
    • 否则,将 L[i] 设为栈顶元素的索引加 1(因为索引是从 0 开始的)。
  2. 计算 R(i)

    • 使用一个栈来维护右侧元素的索引。对于每个元素 a[i],我们在栈中找到右侧最近的大于 a[i] 的元素。
    • 如果栈为空,说明右侧没有大于 a[i] 的元素,将 R[i] 设为 0。
    • 否则,将 R[i] 设为栈顶元素的索引加 1。
  3. 计算 MAX(i)

    • 对于每个元素 a[i],计算 MAX(i) = L(i) * R(i) 并找出最大值。

复杂度分析

  • 时间复杂度

    • 我们对每个元素访问一次并进行栈操作,因此总体时间复杂度为 O(N),其中 N 是数组的长度。
  • 空间复杂度

    • 主要使用了额外的两个数组 L 和 R 以及一个栈,因此空间复杂度为 O(N)。

总结

通过使用栈,我们能够高效地解决这个问题。栈在处理需要快速查找最近满足某种条件的元素的问题上非常有效。通过一次遍历数组,我们可以计算出每个元素的 L(i) 和 R(i),并进而计算出每个元素的 MAX(i)。最终,我们可以在 O(N) 时间复杂度内找到 MAX(i) 的最大值。这种方法不仅高效,而且具有较低的空间复杂度,非常适合大规模数据的处理。