返回

用单调栈与前缀和的思想巧妙解决 leetcode 1856:最大子序积

后端

破解最大子序乘积的谜团:单调栈与前缀和的巧妙结合

引言

踏入算法题的精彩世界,leetcode 1856:最大子序积会让你大开眼界。它不仅考验你的算法思维,更让你领略单调栈与前缀和的巧妙结合。跟随我们的探索之旅,我们将深入剖析这道难题,让你恍然大悟。

解题思路

单调栈:识别合法序列

想象你面前有一座山峰,山的两边都是陡峭的悬崖。我们的目标是找到最高的山峰,但前提是,这段山坡上不存在任何低谷。而单调栈正是我们在这座算法山峰上寻找最高峰的利器。

单调栈是一种数据结构,它总是维护一个递增或递减的元素序列。在我们的场景中,我们将单调栈用于识别连续子序列,这些子序列中的最小值始终大于或等于 1。当我们遍历数组时,我们会将元素依次压入单调栈中。如果遇到一个比栈顶元素小的元素,说明这座山峰出现了低谷,因此我们将栈顶元素弹出,直到栈顶元素小于或等于当前元素。

前缀和:计算子序列乘积

有了单调栈识别出的合法序列,我们接下来需要计算每个序列的乘积。这里就轮到前缀和闪亮登场了。

前缀和是一种数组,它包含数组中每个元素的前缀和。利用前缀和,我们可以轻松计算子序列的乘积。只需计算子序列第一个元素和最后一个元素的前缀和之差即可。

代码示例

def maxProduct(nums):
    stack = []
    prefix_sum = [0] * len(nums)
    prefix_sum[0] = nums[0]
    for i in range(1, len(nums)):
        prefix_sum[i] = prefix_sum[i - 1] + nums[i]

    max_product = float('-inf')
    for i in range(len(nums)):
        if not stack or nums[i] >= nums[stack[-1]]:
            stack.append(i)
        else:
            while stack and nums[i] < nums[stack[-1]]:
                top = stack.pop()
                product = prefix_sum[i] - (prefix_sum[stack[-1]] if stack else 0)
                max_product = max(max_product, product)
            stack.append(i)

    while stack:
        top = stack.pop()
        product = prefix_sum[len(nums) - 1] - (prefix_sum[stack[-1]] if stack else 0)
        max_product = max(max_product, product)

    return max_product

结语

leetcode 1856:最大子序积看似复杂,但通过巧妙地结合单调栈和前缀和,我们可以轻松破解它。希望这篇博客能让你领略算法的魅力,也希望你继续探索算法世界的奥秘。

常见问题解答

  1. 为什么单调栈能够识别合法序列?
    单调栈确保了连续子序列中没有比其边界更小的元素,从而满足题目中的最小值大于或等于 1 的条件。

  2. 前缀和是如何帮助计算子序列乘积的?
    前缀和提供了子序列第一个元素和最后一个元素之间的总和,而子序列的乘积就是这个总和。

  3. 算法的时间复杂度是多少?
    算法的时间复杂度为 O(n),其中 n 为数组的长度。

  4. 算法的空间复杂度是多少?
    算法的空间复杂度为 O(n),其中 n 为数组的长度。

  5. 除了单调栈和前缀和,还有哪些其他方法可以解决这个问题?
    还有其他方法,例如动态规划,但单调栈和前缀和的结合通常是最有效和最简单的解决方案。