字节跳动2018算法笔试第二题

题目:

给定一个数组序列, 需要求选出一个区间, 使得该区间是所有区间中经过如下计算的值最大的一个:区间中的最小数 * 区间所有数的和最后程序输出经过计算后的最大值即可,不需要输出具体的区间。

如给定序列 [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)

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值