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

78 阅读4分钟

题目: 小R手上有一个长度为n的数组(n>0),数组中的元素分别来自集合[0,1,2,4,8,16,32,64,128,256512,1024]。小R想从这个数组中选取一段连续的区间,得到可能的最大乘积。 你需要帮助小R找到最大乘积的区间,并输出这个区间的起始位置x和结束位置y(x≤ y)。如果存在多个区间乘积相同的情况,优先选择x更小的区间;如果x相同,选择y更小的区间。 注意:数组的起始位置为 1,结束位置为 n。

要解决这个问题,我们需要在给定的数组中找到一个连续子区间,其乘积最大。给定的元素来自特定的集合,这些元素是2的幂次方(包括0),因此乘积的变化会比较剧烈。我们需要高效地找出最大乘积子区间,并返回该区间的起始和结束位置。

解决思路

  1. 动态规划的思想: 我们可以通过动态规划的方式计算当前子区间的乘积。每次遍历到数组中的一个元素时,我们可以计算包含该元素的子区间的乘积,并记录下当前最大乘积以及对应的区间。

  2. 如何跟踪最大乘积:

    • 使用两个变量 max_productmin_product,分别跟踪当前的最大乘积和最小乘积。由于数组中可能有负数,最小乘积可能会成为最大乘积。
    • 维护一个变量 start_index 来记录当前最大乘积的区间的起始位置。
  3. 步骤:

    • 对每个位置的元素,分别考虑它和之前的最大/最小乘积的组合,计算出新的最大/最小乘积。
    • 如果当前的乘积大于之前的最大乘积,就更新最大乘积和对应的区间。
    • 如果乘积相同,则根据题意选择更小的区间。
  4. 考虑边界条件:

    • 数组的长度 n > 0
    • 如果数组元素包含 0,会导致乘积为零,因此需要特别处理。

完整的代码实现

def solution(n: int, arr: list[int]) -> list[int]:
    # 初始的最大乘积和最小乘积,初始位置
    max_product = float('-inf')
    min_product = float('inf')
    
    # 最终的答案区间
    best_start = 0
    best_end = 0
    
    # 当前区间的起始索引
    start_index = 0
    
    # 用于当前乘积的变量
    current_max = 1
    current_min = 1
    
    for i in range(n):
        num = arr[i]
        
        # 处理0,0会使得乘积清空
        if num == 0:
            current_max = 1
            current_min = 1
            start_index = i + 1
            continue
        
        # 临时保存当前的最大和最小乘积
        temp_max = current_max
        temp_min = current_min
        
        # 计算新的最大最小乘积
        current_max = max(num, temp_max * num, temp_min * num)
        current_min = min(num, temp_max * num, temp_min * num)
        
        # 如果找到一个新的最大乘积,更新结果
        if current_max > max_product:
            max_product = current_max
            best_start = start_index + 1  # 1-based index
            best_end = i + 1  # 1-based index
        elif current_max == max_product:
            # 如果乘积相同,选择更小的区间
            if start_index + 1 < best_start or (start_index + 1 == best_start and i + 1 < best_end):
                best_start = start_index + 1
                best_end = i + 1
    
    return [best_start, best_end]


if __name__ == "__main__":
    # 测试用例
    print(solution(5, [1, 2, 4, 0, 8]))  # [1, 3]
    print(solution(7, [1, 2, 4, 8, 0, 256, 0]))  # [6, 6]

代码说明:

  • 初始化变量:

    • max_product:用于记录到当前为止的最大乘积。
    • min_product:用于记录到当前为止的最小乘积。
    • best_startbest_end:记录最大乘积区间的起始和结束位置。
    • current_maxcurrent_min:分别是当前考虑到的区间的最大和最小乘积。
    • start_index:记录当前考虑区间的起始位置。
  • 遍历数组:

    • 对每个元素 arr[i],我们首先考虑它与前面已经计算出的最大/最小乘积的组合,得到新的最大和最小乘积。
    • 如果 arr[i] == 0,乘积会重置为1,因此需要特别处理。
  • 更新最大乘积:

    • 如果当前的 current_max 大于 max_product,则更新最大乘积,并记录该区间的起始和结束位置。
    • 如果当前乘积与已有最大乘积相同,优先选择更小的区间(首先比较起始位置,再比较结束位置)。

复杂度分析:

  • 时间复杂度: 每次遍历数组一次,操作的时间复杂度是 O(n),其中 n 是数组的长度。
  • 空间复杂度: 使用常数空间 O(1),除了输入数组外,额外的空间消耗较小。

测试

print(solution(5, [1, 2, 4, 0, 8]))  # [1, 3]
print(solution(7, [1, 2, 4, 8, 0, 256, 0]))  # [6, 6]
print(solution(5, [2, 2, 2, 2, 2]))  # [1, 5]

以上是对该题解题思路的思考。