「这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战」
给定一个整数数组
nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6 。
复制代码
暴力解法
看到题目,最容易实现的就是暴力求解,对所有子数组集合完整进行一次遍历计算,时间复杂度为O(n^2):
func maxSubArray(nums []int) int {
m := nums[0]
for i := 0; i < len(nums); i++ {
for j := i; j < len(nums); j++ {
s := 0
for t := i; t <= j; t++ {
s += nums[t]
}
if s > m {
m = s
}
}
}
return m
}
复制代码
当然,不出意外的超时了:
贪心算法
通过观察,我们不难发现:当一串子序列向后拓展时,若此时本序列和已经小于0了,那么我们不如直接放弃该子串,直接从下一个元素开始重新构建连续子串。
举个简单的例子,从-2
开始构建连续子序列,后面元素为1
,那么要想把1
加到该子序列中,得到子序列-2, 1
序列和为-1
。这肯定是不合理的,因为我们直接放弃-2
,重新从1
开始构建子序列1
,序列和为1
大于上述子序列。
因此,我们可以通过该特性以子序列和为负数作为分界条件,来求子序列的局部最优解。
同时,每当局部最优解更新更新时,都可以与全局最优进行比对,若大于全局最优解,则更新。
只需一次遍历,就能得到结果,时间复杂度为O(n)。
代码实现如下:
func maxSubArray(nums []int) int {
m := nums[0]
tmp := 0
for i := 0; i < len(nums); i++ {
tmp += nums[i]
if tmp > m {
m = tmp
}
if tmp < 0 {
tmp = 0
}
}
return m
}
复制代码