滑动窗口示例 | 豆包MarsCode AI刷题

75 阅读5分钟

原题描述

小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

解读

在这道题中,我们需要找到一个数组中连续区间,使其乘积最大。数组的元素来自于集合 ([0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]),并且可能包含 0。由于 0 会将乘积清零,我们可以把数组划分成多个不包含 0 的子数组分别处理。最终,我们要返回最大乘积的区间起始和结束位置。

解题思路

这道题的核心在于如何高效计算每个子数组的最大乘积。

  1. 分割子数组:遇到 0 时,清除乘积并重新开始计算,将数组分成若干不含 0 的子数组。
  2. 双向遍历求最大乘积:对每个子数组,从左到右和从右到左各遍历一次,以防负数干扰。例如,当区间中包含负数时,乘积可能通过双向遍历的方式找到最大值。
  3. 维护区间位置:在所有子数组中选择乘积最大的区间,并按题目要求优先选择起始位置更小的区间。

具体解题过程

1:初始化与遍历

首先,我们遍历整个数组,跳过 0 并记录每个不包含 0 的子数组的起始和结束位置。使用以下代码完成:

max_product = 0
best_x, best_y = 1, 1
i = 0

while i < n:
    if arr[i] == 0:
        i += 1
        continue

    # 找到不包含0的子数组
    start = i
    while i < n and arr[i] != 0:
        i += 1
    end = i - 1
2:计算每个子数组的最大乘积

对每个不包含 0 的子数组,调用 find_max_product_in_subarray 函数进行双向遍历,找到最大乘积和对应的区间位置。代码如下:

def find_max_product_in_subarray(arr, start, end):
    max_product = float('-inf')
    current_product = 1
    x, y = start, start
    temp_start = start

    # 从左到右遍历
    for i in range(start, end + 1):
        current_product *= arr[i]
        if current_product > max_product:
            max_product = current_product
            x, y = temp_start, i
        if current_product == 0:  # 遇到0重置
            current_product = 1
            temp_start = i + 1

    # 从右到左遍历
    current_product = 1
    temp_start = end
    for i in range(end, start - 1, -1):
        current_product *= arr[i]
        if current_product > max_product:
            max_product = current_product
            x, y = i, temp_start
        if current_product == 0:  # 遇到0重置
            current_product = 1
            temp_start = i - 1

    return max_product, x, y
3:更新全局最大乘积

在主函数中,我们将所有子数组的最大乘积进行比较,更新全局最大乘积并记录最佳区间位置:

max_subproduct, x, y = find_max_product_in_subarray(arr, start, end)
if max_subproduct > max_product:
    max_product = max_subproduct
    best_x, best_y = x + 1, y + 1  # 转换为从1开始的索引
elif max_subproduct == max_product:
    if x + 1 < best_x or (x + 1 == best_x and y + 1 < best_y):
        best_x, best_y = x + 1, y + 1

代码完整实现

完整代码:

def solution(n: int, arr: list[int]) -> list[int]:
    def find_max_product_in_subarray(arr, start, end):
        max_product = float('-inf')
        current_product = 1
        x, y = start, start
        temp_start = start

        # 从左到右遍历
        for i in range(start, end + 1):
            current_product *= arr[i]
            if current_product > max_product:
                max_product = current_product
                x, y = temp_start, i
            if current_product == 0:
                current_product = 1
                temp_start = i + 1

        # 从右到左遍历
        current_product = 1
        temp_start = end
        for i in range(end, start - 1, -1):
            current_product *= arr[i]
            if current_product > max_product:
                max_product = current_product
                x, y = i, temp_start
            if current_product == 0:
                current_product = 1
                temp_start = i - 1

        return max_product, x, y

    max_product = 0
    best_x, best_y = 1, 1

    i = 0
    while i < n:
        if arr[i] == 0:
            i += 1
            continue
        start = i
        while i < n and arr[i] != 0:
            i += 1
        end = i - 1
        max_subproduct, x, y = find_max_product_in_subarray(arr, start, end)
        
        if max_subproduct > max_product:
            max_product = max_subproduct
            best_x, best_y = x + 1, y + 1
        elif max_subproduct == max_product:
            if x + 1 < best_x or (x + 1 == best_x and y + 1 < best_y):
                best_x, best_y = x + 1, y + 1

    return [best_x, best_y]

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])
    print(solution(8, [1, 2, 4, 8, 0, 256, 512, 0]) == [6, 7])

MarsCode提供的思路与提示

算法步骤

  1. 遍历数组:从左到右遍历数组,找到不包含0的子数组。
  2. 处理子数组:对于每个不包含0的子数组,计算其乘积,并记录最大乘积及其对应的区间。
  3. 考虑0的情况:如果遇到0,则重置当前乘积,并继续遍历。
  4. 比较和更新:在遍历过程中,不断比较当前乘积与最大乘积,更新最大乘积及其对应的区间。

具体步骤

  1. 初始化:初始化最大乘积为0,最佳区间为 [1, 1]
  2. 遍历数组:从左到右遍历数组,跳过0。
  3. 找到不包含0的子数组:记录子数组的起始和结束位置。
  4. 计算子数组的乘积:对于每个子数组,计算其乘积,并记录最大乘积及其对应的区间。
  5. 更新最大乘积:如果当前子数组的乘积大于最大乘积,或者乘积相同但区间更优,则更新最大乘积及其对应的区间。

一点心得体会

在这道题中,通过双向遍历子数组来计算最大乘积是一个创新且有效的思路。这样的处理方式不仅避免了负数干扰,还保证了算法的高效性。使用双向扫描时,我们同时考虑了优先选择区间起始位置和结束位置更小的需求,使得代码在计算最大乘积的同时符合题目要求。

MarsCode AI 提供的双向遍历和分治策略,简化了负数干扰和 0 的处理,最终实现了最优解。