描述
给定一个长度为 n 的数组 arr ,返回其中任意连续子数组的最大累加和
题目保证没有全为负数的数据
数据范围:1<=n<=100000,数组中元素值|val|<=100
要求:时间复杂度为O(n),空间复杂度为O(1)
示例1
输入: [1, -2, 3, 5, -2, 6, -1]
返回值:12
说明:[3,6]范围内的子数组之和最大,3+5-2+6=12
示例2
输入: [1]
返回值:1
class Solution:
def maxsumofSubarray(self , arr ):
# write code here
SUM = MAX = arr[0]
for i in range(1, len(arr)):
if SUM <= 0: #如果之前的累加和小于等于0,可以舍弃前缀
SUM = arr[i]
else: #否则累加
SUM += arr[i]
MAX = max(SUM,MAX)
return MAX
记录一下思考
一开始也是懵逼而且很多题解并没有说为什么可以直接舍弃前缀以及前缀的子数组可能包含结果。
首先考虑极其简单的一种情况,要判断的数组中只有两个数[-1, 2],其中最大的组合是2。原因是-1只会使数组和减少,由此不难发现如果一个子数组是由负数开头那么这个负数一定是可以被优化掉的。
现在将情况扩展,数组现在由n个数字组成,参照上面的情况我们总是可以将子数组看成两个数字pre和cur,pre即为前缀的和,如果前缀的和小于0那么总是可以被优化掉。
现在问题的关键就变成了如何寻找pre,细心的你可能发现了我们只对数组进行了一次遍历,总是舍弃前缀和小于等于0的前缀。但是我们如何保证前缀的子数组是不可能是我们要找的前缀呢?个人认为这一点是理解这个算法的关键。例如数组[3, -2, -3, 5, -2, 6],我们可以看出当前缀为[3, -2, -3]时前缀的和首次小于0,此时我们将前缀和重置为0,相当于我们否认了这个前缀以及这个前缀的所有子数组(e.g. [-2, -3], [-3])成为解的可能,而直接跳转到cur,为什么会这样?首先因为数组必须是连续的,则所有前缀可能的子数组都是通过删除左边元素得到的(即前缀的前缀),我们知道在非法前缀的最后一个数字之前,前缀总是大于0的,所以我们从最左边删除等价于删除大于0的数,这就使得这些前缀的子数组只可能比前缀小从而更不可能成为前缀。
发现很多解释并没有给出算法的理由,特地研究了一下,也是当个备忘录。