题目: 小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),因此乘积的变化会比较剧烈。我们需要高效地找出最大乘积子区间,并返回该区间的起始和结束位置。
解决思路
-
动态规划的思想: 我们可以通过动态规划的方式计算当前子区间的乘积。每次遍历到数组中的一个元素时,我们可以计算包含该元素的子区间的乘积,并记录下当前最大乘积以及对应的区间。
-
如何跟踪最大乘积:
- 使用两个变量
max_product和min_product,分别跟踪当前的最大乘积和最小乘积。由于数组中可能有负数,最小乘积可能会成为最大乘积。 - 维护一个变量
start_index来记录当前最大乘积的区间的起始位置。
- 使用两个变量
-
步骤:
- 对每个位置的元素,分别考虑它和之前的最大/最小乘积的组合,计算出新的最大/最小乘积。
- 如果当前的乘积大于之前的最大乘积,就更新最大乘积和对应的区间。
- 如果乘积相同,则根据题意选择更小的区间。
-
考虑边界条件:
- 数组的长度
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_start和best_end:记录最大乘积区间的起始和结束位置。current_max和current_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]
以上是对该题解题思路的思考。