问题描述
小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]`
解释:最大乘积为arr[0]乘到arr[2]即1*2*4=8
测试样例2
输入:`n = 7, arr = [1, 2, 4, 8, 0, 256, 0]`
输出:`[6, 6]`
解释:最大乘积为arr[5]即256
问题分析
我们把题目分成一条一条的来分析:
-
“数组中的元素分别来自集合
[0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]”这句话告诉我们数组元素不是0就是1就是比1大的正整数,扩展连续区间时,如果最右端的元素非1非0,则乘积增大;如果最右端的元素为1,则乘积不变;如果最右端的元素为0,则前功尽弃,乘积变为0,因此我们要跳过0。
-
“如果存在多个区间乘积相同的情况,优先选择
x更小的区间;如果x相同,选择y更小的区间。”这句话告诉我们除了0以外,要格外注意处理1的情况。例如
[1,128,0,0,16,16,512,1,0,8]这样一个区间,可以看到如果不考虑1的边界情况,我们会取到[16,16,512,1]这样一个子区间作为答案,因为显然它的成绩最大,但是一个需要注意的地方是由于末尾乘过1,这个最大乘积在乘1前就已经出现过,即子区间[16,16,512]的乘积也是最大,而题目要求我们成绩相同的情况下,且x也相同的情况下,选择y更小的区间。因此我们每更新一个最大乘积时,需要格外数一下末尾1的个数num_of_1,右下标righ减去1的个数num_of_1即可。
-
“注意:数组的起始位置为
1,结束位置为n”返回答案时,下标值均+1即可。
参考代码
def solution(n, data):
# Edit your code here
left = -1 #初始化值
right = -1
max_product = -1
index = 0
while index < n:
while index < n and data[index] == 0: #跳过0
index += 1
tmp = index
product = 1
while index < n and data[index] != 0: #连乘,遇到0时停止
product *= data[index]
index += 1
if product > max_product: #如果乘积大于最大乘积,更新值
max_product = product
left = tmp
i = index - 1
count_of_1 = 0
while i >= 0 and data[i] == 1: #计算区间末尾1的个数,right向前倒退1的个数即可。
count_of_1 += 1
i -= 1
right = index - 1 - count_of_1
return [left + 1, right + 1]