问题描述
小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]
解题思路
-
初始化:
- 将
max_product初始化为负无穷大,确保任何乘积都能更新它。 - 将
start和end初始化为 0。 - 将
temp_start初始化为 0。 - 将
product初始化为 1。
- 将
-
遍历数组:
- 对于数组中的每个元素
arr[i]:- 如果
arr[i]为 0,表示当前区间结束。检查当前product是否大于max_product,如果是,更新max_product和对应的区间start和end。然后重置product和temp_start。 - 如果
arr[i]不为 0,将arr[i]乘到product上。检查当前product是否大于max_product,如果是,更新max_product和对应的区间start和end。
- 如果
- 对于数组中的每个元素
-
处理最后一个区间:
- 在遍历结束后,检查最后一个区间的乘积是否大于
max_product,如果是,更新max_product和对应的区间start和end。
- 在遍历结束后,检查最后一个区间的乘积是否大于
-
返回结果:
-
返回
start + 1和end + 1,因为题目要求的区间起始位置是从 1 开始的。
-
代码实现
from typing import List
def solution(n: int, arr: List[int]) -> List[int]:
max_product = float('-inf')
start = 0
end = 0
temp_start = 0
product = 1
zero_count = 0
for i in range(n):
if arr[i] == 0:
if product > max_product:
max_product = product
start = temp_start
end = i - 1
product = 1
zero_count += 1
temp_start = i + 1
else:
product *= arr[i]
if product > max_product:
max_product = product
start = temp_start
end = i
if product > max_product:
max_product = product
start = temp_start
end = n - 1
return [start + 1, end + 1]
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])
知识点总结
-
动态规划:
- 动态规划是一种通过将问题分解为子问题来解决复杂问题的方法。在这个问题中,可以使用动态规划来记录每个区间的乘积,并逐步更新最大乘积和对应的区间。
- 动态规划通常涉及状态定义、状态转移方程和边界条件的处理。
-
滑动窗口:
- 滑动窗口是一种常见的算法技巧,用于在数组或字符串中找到满足特定条件的子数组或子字符串。在这个问题中,可以使用滑动窗口来动态调整区间的起始和结束位置,以找到最大乘积的区间。
- 滑动窗口通常涉及两个指针(起始指针和结束指针),通过移动指针来调整窗口的大小。
-
贪心算法:
- 贪心算法是一种在每一步选择中都采取当前状态下最优的选择,以期望达到全局最优的算法。在这个问题中,可以使用贪心算法来选择当前乘积最大的区间。
- 贪心算法通常需要证明其正确性,即每一步的最优选择能够保证最终结果的最优性。