最大乘积区间问题
一、问题重现
问题描述
小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, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]。 - 如果存在多个乘积相同的子数组,优先选择起始位置
x更小的子数组;如果x相同,选择结束位置y更小的子数组。
-
数据结构选择:
- 使用两个指针
i和j来表示当前考虑的子数组的起始和结束位置。 - 使用一个变量
pro来记录当前子数组的乘积。 - 使用
max_product来记录当前找到的最大乘积。 - 使用
begin和end来记录最大乘积子数组的起始和结束位置。
- 使用两个指针
-
算法步骤:
- 初始化
max_product为0,begin和end为0,i和j为0,pro为1。 - 使用一个循环遍历数组,每次将当前元素乘到
pro中。 - 如果当前元素为0且不是最后一个元素,则跳过该零值并重新开始计算乘积。
- 如果当前乘积
pro大于max_product,则更新max_product和对应的区间begin和end。 - 返回包含起始和结束位置的列表,位置从1开始计数。
- 初始化
算法实现
-
变量初始化:
max_product初始化为0,用于记录最大乘积。begin和end初始化为0,用于记录最大乘积子数组的起始和结束位置。i和j初始化为0,用于表示当前考虑的子数组的起始和结束位置。pro初始化为1,用于记录当前子数组的乘积。
-
循环遍历:
- 使用
while循环遍历数组,每次将当前元素data[j]乘到pro中。 - 如果当前元素
data[j]为0且不是最后一个元素,则跳过该零值并重新开始计算乘积,即将i更新为j + 1,并将pro重置为1。 - 如果当前乘积
pro大于max_product,则更新max_product和对应的区间begin和end。 j每次循环递增1。
- 使用
-
返回结果:
- 返回包含起始和结束位置的列表,位置从1开始计数。
三、代码实现
def solution(n, data):
max_product = 0
begin = 0
end = 0
i = 0
j = 0
pro = 1
while j < n:
pro *= data[j]
if data[j] == 0 and j < n - 1:
i = j + 1
pro = 1
if pro > max_product:
max_product = pro
begin = i
end = j
j += 1
return [begin + 1, end + 1]
四、算法复杂度
时间复杂度
-
外层循环:
O(n)。 -
内层操作:
O(1)。 -
总时间复杂度:
O(n)。
空间复杂度
O(1)