动态规划思想
先上代码
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum = Math.max(nums[i], sum + nums[i]);
max = Math.max(sum , max);
}
return max;
}
}
设sum[i]为以第i个元素结尾且和最大的连续子数组。假设对于元素i,所有以它前面的元素结尾的子数组的长度都已经求得,那么以第i个元素结尾且和最大的连续子数组实际上,要么是以第i-1个元素结尾且和最大的连续子数组加上这个元素,要么是只包含第i个元素,即sum[i]= max(sum[i-1] + a[i], a[i])。可以通过判断sum[i-1] + a[i]是否大于a[i]来做选择,而这实际上等价于判断sum[i-1]是否大于0。由于每次运算只需要前一次的结果,因此并不需要像普通的动态规划那样保留之前所有的计算结果,只需要保留上一次的即可,因此算法的时间和空间复杂度都很小。
作者:腾阳
来源:CSDN
原文:https://blog.csdn.net/weixin_41931602/article/details/82891149
版权声明:本文为博主原创文章,转载请附上博文链接!
个人理解:
比如我们我们有这样一个数组 1, 2, 3,我们要判断最大的子序列和,我们先列出所有情况:
3 | 32 | 321 |
2 | 21 | |
1 |
我们从数组后面往前找,在所有的子序列中比较最大值。现在我们按照上面的思想sum[i]= max(sum[i-1] + a[i], a[i]),先从最后一位3开始看起,我们把以最后一个数3的所有子序列列出来并分为两部分,一部分是a[i]即3,另一部分是(sum[i-1] + a[i])
最后一个数 | 剩下的子序列 |
---|---|
3 | 32, 321, 2, 21,1 |
后面的序列实际可以拆成 3 + max(21,2),括号里的序列其实就是以2为最后一位数字的最大序列和,依次递归还可以拆成以1为最后数字的最大序列和。所以我们最终能推出动态规划的状态方程sum[i]= max(sum[i-1] + a[i], a[i])。
接着再按照代码的顺序就可以理解。
我们还可以顺便变化一下方程,sum[i-1] + a[i] < a[i] ⇒ sum[i-1] < 0,这个公式说明,如果我们在计算sum和的时候,加上最后一个数如果碰到sum <0时便可以直接丢弃,因为这时sum[i]一定不是最大的子序列和,a[i]此时才是最大的。贴上代码。
class Solution {
public int maxSubArray(int[] nums) {
int sum = 0, sumMax = nums[0];
for(int i = 0; i < nums.length; i++){
sum += nums[i];
if(sum > sumMax){
sumMax = sum;
}
if(sum < 0){
sum = 0;
}
}
return sumMax;
}
}