一、题目分析
题目:给定一个长度为 n 的数组,数组元素来自集合 [0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]。从中选取一段连续区间,使得该区间内的元素乘积最大,并输出该区间的起始位置 x 和结束位置 y(从1开始计数)。
思考过程:
目标是在数组中找到一段连续的区间,使得该区间内元素的乘积最大。 题目在双指针的分类里,考虑使用双指针做题。
需要注意的点有:
数组元素为0时:
0 会将乘积变为 0,所以需要在遇到 0 时跳过或者重新开始计算新的子数组。
有多个相同乘积的区间时: 优先选择起始位置较小的区间,如果起始位置相同,则选择结束位置较小的区间。
边界条件为:
如果数组中全是 0,需要返回 [-1, -1] 表示没有有效的区间。
题目限定数组长度 n 大于 0。
可以得出以下这个基本思路:
(1)需要遍历数组,并在每个起始点开始寻找最大乘积的连续子数组。
(2)使用嵌套循环来遍历所有可能的连续子数组。
(3)当找到一个新的最大乘积时,更新最大乘积和对应的起始位置 start 和结束位置 end。
(4)注意处理数组中包含 0 的情况,因为 0 会使得乘积变为零,并且分割连续的子数组。
举个例子
假设有一个数组 [1, 2, 4, 0, 8]:
从 [1, 2, 4] 可以得到乘积 1 * 2 * 4 = 8
0 则是一个分割符,使得我们重新开始计算新的区间
8 单独一项,其乘积为 8
在这个例子中,最大乘积为 8,出现在 [1, 2, 4] 和 [8] 两个区间中,但 [1, 2, 4] 的起始位置较小,所以选择 [1, 2, 4]。
二、解答题目
步骤解析:
第一步:初始化:
-
max_product = float('-inf')用于存储当前找到的最大乘积值,初始值为负无穷。 -
start和end用于存储最大乘积区间的起始和结束位置,初始值为-1。
第二步:创建外层循环
用于遍历数组的每个元素:
for i in range(n):
if arr[i] == 0:
continue
-
外层循环从数组的第一个元素开始遍历。
-
如果当前元素是
0,则跳过这个元素,继续下一个,因为0会将乘积变为0。
第三步:创建内层循环
用于计算从当前位置开始的所有连续子数组的乘积:
p = 1 # 初始化乘积,p为product的简写
for j in range(i, n):
if arr[j] == 0:
break # 遇到0跳出内循环
p *= arr[j] # 计算子数组乘积
- 初始化
p为1,用于存储当前子数组的乘积。 - 内层循环从当前
i开始,继续向右扩展子数组。 - 如果遇到
0,跳出内层循环,开始下一个i的处理。 - 每次更新子数组乘积
p。
第四步:比较并更新最大乘积和它的区间:
if p > max_product:
max_product = p
start = i
end = j
elif p == max_p:
if i < start or (i == start and j < end):
start = i
end = j
- 如果当前乘积
p大于max_product,则更新max_product以及start和end。 - 如果当前乘积
p等于max_product,则选择起始位置较小或结束位置较小的区间。
第五步:处理边界情况:
if start == -1 or end == -1:
return [-1, -1]
如果没有找到有效的区间(即 start 和 end 仍为-1),返回 [-1, -1]。
最后返回结果:
[start + 1, end + 1]
返回结果时,将 start 和 end 加1,因为题目要求数组的起始位置为 1。
这道简单题就做完了。