题目:
给定一个数组序列, 需要求选出一个区间, 使得该区间是所有区间中经过如下计算的值最大的一个:区间中的最小数 * 区间所有数的和最后程序输出经过计算后的最大值即可,不需要输出具体的区间。
如给定序列 [6 2 1]则根据上述公式, 可得到所有可以选定各个区间的计算值:
- [6] = 6 * 6 = 36;
- [2] = 2 * 2 = 4;
- [1] = 1 * 1 = 1;
- [6,2] = 2 * 8 = 16;
- [2,1] = 1 * 3 = 3;
- [6, 2, 1] = 1 * 9 = 9;
从上述计算可见选定区间 [6] ,计算值为 36, 则程序输出为 36。
输入输出要求:
区间内的所有数字都在[0, 100]的范围内;
输入描述:
第一行输入数组序列长度n,第二行输入数组序列。
对于 50%的数据, 1 <= n <= 10000;
对于 100%的数据, 1 <= n <= 500000;
输出描述:
输出数组经过计算后的最大值。
例子:
输入例子1:
3
6 2 1
输出例子1:
36
思路:
每个元素都可能是某个或多个区间的最小值,所以当最小值确定的时候,区间越大越好。
如果是递增数组,如[1, 2, 3, 4, 5],那么我们可以不用计算所有区间长度为1的结果,也不需要计算前面的诸如1 * (1 + 2)、2 * (2 + 3)之类的区间,因为没有达到最小值是1或2时的最大区间,因此我们可以倒序来计算,这样每次计算的就是最小值一定时的最大区间,如下:
5 * 5 = 25 result = 25
4 * (4 + 5) = 36 result = max(36, 25) = 36
3 *(3 + 4 + 5) = 36 result = max(36, 36) = 36
2 * (2 + 3 + 4 + 5) = 28 result = max(28, 36) = 36
1 * (1 + 2 + 3 + 4 + 5) = 15 result = max(15, 36) = 36
从上可以看出,中间变量是区间的和;
故由上延伸,如果不是递增数组,如[3, 4, 5, 2, 1],我可以建立一个栈stack来存储输入的数字,并保持递增,建立presum来保存stack中每个数字之前大于它的数字之和(这些数字与该数字相连),这样在以stack中的某个数字为最小值时,它的最大区间的和就是presum对应位置的数字与该数字之和,过程可描述如下:
设中间变量区间的和tempsum = 0,
- stack = [3] presum = [0]
- stack = [3, 4] presum = [0, 0]
- stack = [3, 4, 5] presum = [0, 0, 0]
此时后面的数字2小于5,因此我们来计算在2之前比2小的数字之和,以及以前面大于2的数字为最小值的最大区间结果,
- temp = 5,tempsum = 5 + presum[2] = 5, result = 5 * 5 = 25
- temp = 4,tempsum = 4 + 5 + presum[1] = 9,result = max(4 * 9, 25) = 36
- temp = 3,tempsum = 3 + 9 + presum[0] = 12,result = max(3 * 12, 36) = 36
此时stack为空,数字2可以存入stack中,并且presum对应值为12,
- stack = [2] presum = [12]
又因为1小于2,所以我们可以计算以2为最小值的最大区间结果,
- temp= 2,tempsum = 2 + presum[0] = 14,result = max(2 * 14, 36) = 36
此时stack为空,数字1可以存入stack中,并且presum对应值为14,
- stack = [1] presum = [14]
数字1是最后一个数字,所以开始计算以1为最小值的最大区间结果,
temp = 1, tempsum = 1 + presum[0] = 15,result = max(1 * 15, 36) = 36
最后得到最大的值为36。
代码:
# 输入的数组长度
n = int(input())
# 输入的数组序列
arr = [int(x) for x in input().split()]
# 在数组最后加入0是为了能够在最后将所有的情况都计算到
arr.append(0)
# 按照一定的规则压入输入的数字,使其保持递增
stack = []
result = 0
i = 0
# presum对应位置的值是stack对应位置值之前比他大的连续数字之和
presum = []
tempsum = 0 # 临时和
while i < len(arr):
if not stack or arr[i] >= stack[-1]: # i = 0的时候stack是空的,此时先将presum中的值与tempsum的值设为0
# presum对应位置的值是stack对应位置值之前比它大的连续数字之和
presum.append(tempsum)
tempsum = 0
stack.append(arr[i]) # 递增
i += 1
else: # 当
# temp区间最小值
temp = stack.pop(-1)
# tempsum 区间所有数的和
tempsum += (temp+presum.pop())
result = max(tempsum*temp, result)
print(result)
代码取自https://blog.csdn.net/weixin_42001089/article/details/84203651,自己又捋了一遍关系,给自己做个笔记吧~~~
同样参考了https://www.cnblogs.com/Elaine-DWL/p/11210621.html,自己写了一个python的,但是AC了70%,还没有找到原因,代码附上:
import sys
def maxSubArray(length, nums) -> int:
result = 0
for i in range(length):
Min = nums[i]
Sum = nums[i]
if i > 0:
# 向左找边界
for m in range(i - 1, -1, -1):
if nums[m] > Min:
Sum = Sum + nums[m]
else:
break
if i < length - 1:
# 向右找边界
for n in range(i + 1, length):
if nums[n] > Min:
Sum = Sum + nums[n]
else:
break
# 求乘积
tmp = Min * Sum
if tmp > result:
result = tmp
print(result)
length = int(sys.stdin.readline().strip())
nums = list(map(int, ((sys.stdin.readline()).strip()).split()))
maxSubArray(length, nums)