用单调栈与前缀和的思想巧妙解决 leetcode 1856:最大子序积
2024-02-14 00:01:35
破解最大子序乘积的谜团:单调栈与前缀和的巧妙结合
引言
踏入算法题的精彩世界,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 的条件。 -
前缀和是如何帮助计算子序列乘积的?
前缀和提供了子序列第一个元素和最后一个元素之间的总和,而子序列的乘积就是这个总和。 -
算法的时间复杂度是多少?
算法的时间复杂度为 O(n),其中 n 为数组的长度。 -
算法的空间复杂度是多少?
算法的空间复杂度为 O(n),其中 n 为数组的长度。 -
除了单调栈和前缀和,还有哪些其他方法可以解决这个问题?
还有其他方法,例如动态规划,但单调栈和前缀和的结合通常是最有效和最简单的解决方案。