最大乘积区间问题
问题描述
小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]
思路分析
- 乘积计算:连续区间的乘积可以通过逐步计算来实现。如果我们有一个当前乘积,我们可以在遍历数组时用它乘以当前元素,直到遇到0(因为乘以0会使乘积变为0)。
- 重置乘积:当遇到0时,乘积重置为1,且此时我们需要检查之前的乘积是否是最大的。如果是,则记录当前的起始和结束位置。
- 记录最大乘积:在遍历过程中,我们需要维护一个最大乘积及其对应的起始和结束索引。
- 优先选择:在更新最大乘积时,需要确保遵循题目中关于优先选择条件的要求(先比较起始位置,再比较结束位置)。
实现步骤
-
初始化一些变量,如最大乘积
max_product、最大乘积区间的起始和结束位置max_start和max_end。 -
遍历数组,维护当前乘积
current_product和当前区间的起始位置current_start。 -
当遇到0时:
- 检查当前乘积是否大于已记录的最大乘积,如果是,则更新最大乘积和对应位置。
- 重置乘积和起始位置。
-
遍历结束后,最后一次检查(因为最后一段可能不以0结束)。
-
返回最大乘积区间的起始和结束位置。
代码示例
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]
-
初始化变量:
max_product: 用于存储最大乘积,初始为负无穷。max_start,max_end: 用于记录最大乘积子数组的起始和结束索引,初始为-1。current_product: 用于跟踪当前子数组的乘积,初始为1。current_start: 当前子数组的起始索引,初始为0。
-
遍历数组:
- 使用一个
for循环遍历数组arr的每一个元素。
- 使用一个
-
处理零的情况:
-
如果当前元素为零,表示当前子数组结束:
- 检查
current_product是否大于max_product,如果是,则更新max_product和相应的起止索引。 - 如果相等,还需要检查起始和结束索引,以确保找到的子数组是最小的。
- 之后重置
current_product和current_start为下一个元素。
- 检查
-
-
处理非零元素:
- 如果当前元素不为零,将其乘到
current_product中,继续计算当前子数组的乘积。
- 如果当前元素不为零,将其乘到
-
循环结束后的最终检查:
- 遍历完成后,再次检查最后一个子数组(如果没有零结尾)。
- 根据
current_product更新max_product和相应的起止索引。
-
**返回
复杂度分析
- 时间复杂度:O(n),因为我们只需要遍历数组一次。
- 空间复杂度:O(1),只使用了固定数量的变量。
这样就能有效找到数组中乘积最大的连续区间
作者:用户39666198198
链接:juejin.cn/post/743301…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。