【每日一练】区间最大乘积

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_20141867/article/details/81590481

问题描述:

给定一个数组序列, 需要求选出一个区间, 使得该区间是所有区间中经过如下计算的值最大的一个:

区间中的最小数 ×区间所有数的和 最后程序输出经过计算后的最大值即可,不需要输出具体的区间。如给定序列 [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

输出

36

思路:
方法一:暴力求解,遍历数组,以数组中每个数作为区间第一个数往后延伸,边延伸边计算区间最小值和区间和,时间复杂度为 O ( n 2 ) ,(这种方法python实现会超时,只能AC 60%,循环中加入break可以AC 70%)

实现如下:

def calca_multi():
    n = int(input())
    nums = list(map(int, input().split()))
    max_value = float("-inf")
    for i in range(n):
        min_value = nums[i]
        sum_value = 0
        for j in range(i, n):
            # 如果区间有数为0,那么它一定是区间最小值,相乘结果也为0,可以无须往后扩大区间
            if nums[j] == 0:
                break
            sum_value += nums[j]
            if nums[j] < min_value:
                min_value = nums[j]
            max_value = max(max_value, sum_value * min_value)
    print(max_value)

方法二:

类似于问题求直方图中最大矩形面积,使用单调栈保存数组下标,具体原理这里不再赘述,下面只说明出入栈规则(栈中保存的是下标,但是下面为了表述方便,栈中元素即表示栈中下标指示的数组元素):

  • 如果栈为空或者当前数大于等于栈顶元素,下标入栈
  • 如果当前数小于栈顶元素,或者遍历结束但栈不为空,栈顶元素出栈,作为区间最小值,同时它也是区间的右边界,区间的左边界为出栈后栈顶下标+1。

具体代码实现如下:

def calca_multi():
    n = int(input())
    nums = list(map(int, input().split()))
    if n == 0:
        return 0
    # 预处理,先将累计和保存;若在出栈时再计算区间和,超时AC 80%
    pre_sum = [nums[0]]
    for i in range(1, n):
        pre_sum.append(pre_sum[-1] + nums[i])
    # 先将第一个数字下标压入栈
    index_stack = [0]
    max_multi = 0
    curindex = 1
    # 数组遍历结束但是栈不为空时仍要继续
    while curindex < n or (curindex == n and len(index_stack) > 0):
        # 当栈为空或者当前数大于等于栈顶元素,下标入栈
        if curindex < n and (len(index_stack) == 0 or nums[curindex] >= nums[index_stack[-1]]):
            index_stack.append(curindex)
            curindex += 1
        # 当数组遍历结束或者当前数小于栈顶元素时
        else:
            # 区间最小值为栈顶元素,出栈
            min_num = nums[index_stack.pop()]
            # 如果此时栈为空了,表示已出栈的数字比前面所有数字都小,左边界下标也就是0,否则左边界下标为(下一个元素的索引+1)
            cursum = pre_sum[curindex-1] - (pre_sum[index_stack[-1]] if len(index_stack) > 0 else 0)
            curmax = min_num * cursum
            max_multi = max(max_multi, curmax)
    return max_multi


print(calca_multi())

猜你喜欢

转载自blog.csdn.net/qq_20141867/article/details/81590481