青训营X豆包MarsCode 技术训练营第一课 | 豆包MarsCode AI 刷题

45 阅读4分钟

最大乘积区间问题

问题描述

小R手上有一个长度为 n 的数组 (n > 0),数组中的元素分别来自集合 [0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]。小R想从这个数组中选取一段连续的区间,得到可能的最大乘积。

你需要帮助小R找到最大乘积的区间,并输出这个区间的起始位置 x 和结束位置 y (x ≤ y)。如果存在多个区间乘积相同的情况,优先选择 x 更小的区间;如果 x 相同,选择 y 更小的区间。

注意:数组的起始位置为 1,结束位置为 n


测试样例

样例1:

输入:n = 5, arr = [1, 2, 4, 0, 8]
输出:[1, 3]

样例2:

输入:n = 7, arr = [1, 2, 4, 8, 0, 256, 0]
输出:[6, 6]

样例3:

输入:n = 8, arr = [1, 2, 4, 8, 0, 256, 512, 0]
输出:[6, 7]

思路分析

  1. 乘积计算:连续区间的乘积可以通过逐步计算来实现。如果我们有一个当前乘积,我们可以在遍历数组时用它乘以当前元素,直到遇到0(因为乘以0会使乘积变为0)。
  2. 重置乘积:当遇到0时,乘积重置为1,且此时我们需要检查之前的乘积是否是最大的。如果是,则记录当前的起始和结束位置。
  3. 记录最大乘积:在遍历过程中,我们需要维护一个最大乘积及其对应的起始和结束索引。
  4. 优先选择:在更新最大乘积时,需要确保遵循题目中关于优先选择条件的要求(先比较起始位置,再比较结束位置)。

实现步骤

  1. 初始化一些变量,如最大乘积max_product、最大乘积区间的起始和结束位置max_startmax_end

  2. 遍历数组,维护当前乘积current_product和当前区间的起始位置current_start

  3. 当遇到0时:

    • 检查当前乘积是否大于已记录的最大乘积,如果是,则更新最大乘积和对应位置。
    • 重置乘积和起始位置。
  4. 遍历结束后,最后一次检查(因为最后一段可能不以0结束)。

  5. 返回最大乘积区间的起始和结束位置。

代码示例


 

def max_product_subarray(n, arr):
    max_product = float('-inf')
    max_start, max_end = -1, -1
    current_product = 1
    current_start = 0

    for i in range(n):
        if arr[i] == 0:
            # Check if the current product is the maximum
            if current_product > max_product:
                max_product = current_product
                max_start, max_end = current_start + 1, i  # +1 for 1-based index
            elif current_product == max_product:
                # If equal, check for smaller indices
                if (current_start + 1 < max_start) or (current_start + 1 == max_start and i < max_end):
                    max_start, max_end = current_start + 1, i
            # Reset for the next segment
            current_product = 1
            current_start = i + 1
        else:
            current_product *= arr[i]
    
    # Final check after the loop
    if current_product > max_product:
        max_product = current_product
        max_start, max_end = current_start + 1, n  # include the last segment
    elif current_product == max_product:
        if (current_start + 1 < max_start) or (current_start + 1 == max_start and n < max_end):
            max_start, max_end = current_start + 1, n

    return [max_start, max_end]

# 测试样例
print(max_product_subarray(5, [1, 2, 4, 0, 8]))  # 输出:[1, 3]
print(max_product_subarray(7, [1, 2, 4, 8, 0, 256, 0]))  # 输出:[6, 6]
print(max_product_subarray(8, [1, 2, 4, 8, 0, 256, 512, 0]))  # 输出:[6, 7]
  1. 初始化变量:

    • max_product: 用于存储最大乘积,初始为负无穷。
    • max_startmax_end: 用于记录最大乘积子数组的起始和结束索引,初始为-1。
    • current_product: 用于跟踪当前子数组的乘积,初始为1。
    • current_start: 当前子数组的起始索引,初始为0。
  2. 遍历数组:

    • 使用一个 for 循环遍历数组 arr 的每一个元素。
  3. 处理零的情况:

    • 如果当前元素为零,表示当前子数组结束:

      • 检查 current_product 是否大于 max_product,如果是,则更新 max_product 和相应的起止索引。
      • 如果相等,还需要检查起始和结束索引,以确保找到的子数组是最小的。
      • 之后重置 current_product 和 current_start 为下一个元素。
  4. 处理非零元素:

    • 如果当前元素不为零,将其乘到 current_product 中,继续计算当前子数组的乘积。
  5. 循环结束后的最终检查:

    • 遍历完成后,再次检查最后一个子数组(如果没有零结尾)。
    • 根据 current_product 更新 max_product 和相应的起止索引。
  6. **返回

复杂度分析

  • 时间复杂度:O(n),因为我们只需要遍历数组一次。
  • 空间复杂度:O(1),只使用了固定数量的变量。

这样就能有效找到数组中乘积最大的连续区间

作者:用户39666198198
链接:juejin.cn/post/743301…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。