题目
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
代码模板:
class Solution {
public int maxSubArray(int[] nums) {
}
}
分析
这道题的解法非常多,有暴力的循环解法,有二分法,但是我要说一下最巧妙的算发:动态规划。
网上翻阅了一下,看到了有写的很好的论述:
引理1: 以负数开头的子序列不会是最大子序列。
证明:令子序列为{ai, ..., aj}, 其中开头的元素 ai < 0, 则 ai + ... + aj < ai+1+...+aj 显然成立。
引理2:对子序列 {ai, ..., aj} , 如果该子序列满足两个条件:
1. 如果对x取 [i, j) 中的任意整数(包含i,不包含j) sum{ai, ..., ax} >0.
2. sum{ai, ..., aj}<0.
则以该子序列中的任何元素ap开头的以aj为终结的任意子序列的和必定小于0。
证明:从两个条件中易推断出:aj<0, 且由引理1知 以负数开头的连续子序列不可能是最大连续子序列,则: ai > 0.
显然有 0 >= sum{ai, ..., aj} >= sum{ai-1, ..., aj} >= sum{ap, ..., aj}, 其中 p 是[i, j)之间的整数。
反证法:假设sum{ap, ..., aj}>0, p取 [i, j) 之间的整数, 由引理2条件 sum{ai, ..., aj}<0 得出sum{ai, ..., ap-1}<0,该结论违反了引理2中的条件:如果对x取[i, j)中的任意整数(包含i,不包含j) sum{ai, ..., ax} >0. 得证。
由引理1可知,若a[i]<0, 则应跳到a[i+1]作为子序列的开头元素(如果a[i+1]>0);
由引理2可知, 若a[i]+...+a[j]<=0且满足引理2的第一个条件,则应以a[j+1]作为最大连续子序列的开头元素(如果a[j+1]>0). 实质上,引理1是引理2的特例。
引理1和2可归结为该状态方程: maxsum(i)= max( maxsum(i-1)+ary(i), ary(i) ); (也可以由动态规划方法处理的准则:最优子结构”、“子问题重叠”、“边界”和“子问题独立”得到)
通过对给定序列顺序地反复运用引理1和引理2,最终可求得该序列的最大连续子序列。
文章出处:https://www.jianshu.com/p/04c03059e538
总结而言,temp则为之前的数的和,当然如果temp小于0的话,就归0。然后maxValue则为temp和maxValue本身的比较的最大值。我们能保证第一个数肯定是正数,
解答
class Solution {
public int maxSubArray(int[] nums) {
if(nums.length == 1 ){
return nums[0];
}
int temp = 0;
int maxValue = nums[0];
for(int i=0 ; i < nums.length;i++){
temp = temp +nums[i];
maxValue = Math.max(temp,maxValue);
if(temp < 0){
temp = 0;
}
}
return maxValue;
}
}