最大乘积区间问题 | 豆包MarsCode AI刷题

45 阅读3分钟

最近我在练习算法题时遇到了一个有趣的问题——最大乘积区间问题。这个问题要求我们从给定的数组中找出一个连续的子数组,使得这个子数组的乘积最大,并输出这个子数组的起始和结束位置。这个问题虽然看似简单,但仔细思考后发现还是有很多值得探讨的点。

首先,我们要明确题目给出的数组元素集合:[0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]。这些数字都是2的幂次,这意味着它们之间相乘会非常方便,不会产生溢出,并且相乘的结果会迅速增长。但同时,我们也注意到集合中包含0,这是一个特殊值,因为它会使得任何数的乘积都变为0。

那么,我们的思路是什么呢?暴力解法肯定是可以的,但时间复杂度太高,对于大数据集可能会超时。所以我们需要寻找一个更高效的方法。

我开始思考如何利用数组中的元素特性来优化。既然数组中的元素都是2的幂次,那么它们相乘的结果将会非常迅速地增大。这就意味着,如果某个区间的乘积非常大,那么这个区间很可能包含多个较大的数。而0的存在,则会让我们随时归零之前的乘积,所以我们需要动态地更新乘积的最大值以及对应的区间。

这时,动态规划的思想浮现了出来。虽然这不是一个典型的动态规划问题,但我们可以借鉴其“状态转移”的思想。我们遍历数组,维护一个当前的最大乘积和对应的区间,当遇到0时,我们可以选择重新开始计算乘积;当遇到较大的数时,我们更新最大乘积和区间。

不过,还有一个细节需要注意:如果存在多个区间乘积相同的情况,我们要优先选择起始位置更小的区间;如果起始位置相同,则选择结束位置更小的区间。这意味着在更新最大乘积时,我们还需要记录当前最大乘积的起始和结束位置,并在每次更新时进行比较和替换。

通过上述的思考和推理,我渐渐找到了解题的脉络。虽然过程中遇到了一些小麻烦,比如如何高效地处理0和如何记录并更新最大乘积的区间,但总的来说,这个问题的解决方法还是比较直观的。

AC代码

def solution(n, data):
    max_product = 0
    start, end = -1, -1
    current_product = 1
    current_start = 0

    for right in range(n):
        # 更新当前乘积
        current_product *= data[right]

        # 如果当前乘积为0,重置当前乘积和起始位置
        if data[right] == 0:
            current_product = 1
            current_start = right + 1
        else:
            # 更新最大乘积和区间
            if current_product > max_product:
                max_product = current_product
                start = current_start
                end = right
            elif current_product == max_product:
                # 如果乘积相同,优先选择起始位置更小的区间
                if current_start < start or (current_start == start and right < end):
                    start = current_start
                    end = right

    return [start + 1, end + 1]

if __name__ == "__main__":
    # Add your test cases here
    print(solution(5, [1, 2, 4, 0, 8]) == [1, 3])
    print(solution(7, [1, 2, 4, 8, 0, 256, 0]) == [6, 6])