给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
这是一道经典题, 学校里的算法课本里,就有这一道题, 整整三种解法, 从最初级穷举法的O()时间复杂度,到最后的利用动态规划的方法的O(n)。
关于题目中说的进阶方法,使用分治法进行求解, 写起来要麻烦不少,直觉上是觉得分治法是没有必要的,不过博主个人也没有去尝试,就是草草看了别人的实践和理论,有兴趣的同学可以自己去看看。
class Solution {
public int maxSubArray(int[] nums) {
int pre = nums[0];
int sum = 0;
for( int i = 0 ; i < nums.length; i++ )
{
sum += nums[i];
if( pre < sum )
pre = sum;
if( sum < 0 )
sum = 0;
}
return pre;
}
}
1. 这道题不难,如果采用穷举法的话,也是可以解答出来的。
2. 这道题的价值就在于,其中有一个解法使用了动态规划的方法,感兴趣的同学可以查略相关内容。
3. 有个地方可能会比较难理解一些,至少当时博主花了不少时间去理解------就是为什么只需要遍历一次,且不断往下遍历时,每次遍历都直接将新的元素与sum求和,一旦sum小于0,将sum置为0。在详细讲解之前,我想,应该先讲一讲思路比较靠谱,所以继续请同学移步2.3思路一节。(哈哈, 文章结构下次再好好构思一下,这回暂时还是不改了)
4. 好了, 从2.3回来的同学,想必已经有大致的想法了, 对整个代码也基本理解了, 没理解的同学也没有关系,可以继续往下看。
5. 我来解这思路的内容继续往下讲, 举个更加具体的例子,我们试着preSingle来记录单个元素的最大值, preMultiple来记录多个元素的最大值,nums = {-2,1,-3,4,-1,2,1,-5,4}, 按照思路中的描述, 我来大概演示一下过程:
nums = [-2,1,-3,4,-1,2,1,-5,4]
index = 0 // nums[index] = -2
preSingle = -2
sum = -2 // (0,0)
preMultiple = -2
// 多元素序列小于0,从下一个元素重新寻找新的子序列
sum = 0
index = 1 // nums[index] = 1
preSingle = 1
sum = 1 // (1,1)
preMultiple = 1
// 多元素序列大于0,从下一个元素重新寻找新的子序列
index = 2 // nums[index] = -3
preSingle = 1
sum = -2 // (1,2)
preMultiple = 1
// 小于0
sum = 0
index = 3 // nums[index] = 4
preSingle = 4
sum = 4 // (3,3)
preMultiple = 4
// 大于0
index = 4 // nums[index] = -1
preSingle = 4
sum = 3 //(3,4)
preMultiple = 4
// 大于0
index = 5 // nums[index] = 1
preSingle = 4
sum = 5 //(3,5)
preMultiple = 5
// 大于0
index = 6 // nums[index] = 2
preSingle = 4
sum = 6 //(3,6)
preMultiple = 6
....
7. 其实感觉还是没办法直接解释清楚,这个地方确实不是特别好理解,因为需要先要知道以下的要点:
1. 当 a < 0 时, a + b < b
2. 动态规划:记录前面的结果,利用前面的结果来更新后面的结果(很粗浅的解释)
1. 目标:找到最大的子序列和。
2. 输出结果: 单个元素或连续的多个元素的最大子序列和。
3. 对于单个元素作为最大子序列和,就比较好解决了, 只要有个变量一直监视更新就可以了。
4. 多个元素的最大子序列和就要麻烦一些,不过,在寻找多个元素的最大子序列和时,我们是已经找到最大的单个元素了的,有了这个前提就好做了。
5. 另外我还需要有一个元素一直在记录当前的多个元素的最大子序列和。
6. 怎么办才能达到O(n)呢,首先,明确“
”。好了, 有了这个就好理解了;也就是说,如果前面的子序列和小于0,那么继续往这个子序列后增加新元素,其和绝对不会同时超过直接从这个子序列的后一个元素开始的新的子序列或者整个数组的最大单个元素,所以我们直接从这个子序列之后的一个元素开始重新寻找新的子序列。
https://leetcode-cn.com/problems/maximum-subarray/description/