Maximum Subarray连续子序列最大和-动态规划之和的局部最优和全局最优

 

题目描述:

  一个整数数组中的元素有正有负,在该数组中找出一个连续子数组,要求该连续子数组中各元素的和最大,这个连续子数组便被称作最大连续子数组。比如数组{2,4,-7,5,2,-1,2,-4,3}的最大连续子数组为{5,2,-1,2},最大连续子数组的和为5+2-1+2=8。

 

原题链接:  http://oj.leetcode.com/problems/maximum-subarray/  
这是一道非常经典的动态规划的题目,用到的思路我们在别的动态规划题目中也很常用,以后我们称为”局部最优和全局最优解法“。
基本思路是这样的,在每一步,我们维护两个变量,一个是全局最优,就是到当前元素为止最优的解是,一个是局部最优,就是必须包含当前元素的最优的解。接下来说说动态规划的递推式(这是动态规划最重要的步骤,递归式出来了,基本上代码框架也就出来了)。假设我们已知第i步的global[i](全局最优)和local[i](局部最优),那么第i+1步的表达式是:
local[i+1]=Math.max(A[i], local[i]+A[i]),就是局部最优是一定要包含当前元素,所以不然就是上一步的局部最优local[i]+当前元素A[i](因为local[i]一定包含第i个元素,所以不违反条件),但是如果local[i]是负的,那么加上他就不如不需要的,所以不然就是直接用A[i];
global[i+1]=Math(local[i+1],global[i]),有了当前一步的局部最优,那么全局最优就是当前的局部最优或者还是原来的全局最优(所有情况都会被涵盖进来,因为最优的解如果不包含当前元素,那么前面会被维护在全局最优里面,如果包含当前元素,那么就是这个局部最优)。

接下来我们分析一下复杂度,时间上只需要扫描一次数组,所以时间复杂度是O(n)。空间上我们可以看出表达式中只需要用到上一步local[i]和global[i]就可以得到下一步的结果,所以我们在实现中可以用一个变量来迭代这个结果,不需要是一个数组,也就是如程序中实现的那样,所以空间复杂度是两个变量(local和global),即O(2)=O(1)。
代码如下: 
[java]  view plain  copy
 
  1. public int maxSubArray(int[] A) {  
  2.     if(A==null || A.length==0)  
  3.         return 0;  
  4.     int global = A[0];  
  5.     int local = A[0];  
  6.     for(int i=1;i<A.length;i++)  
  7.     {  
  8.         local = Math.max(A[i],local+A[i]);  
  9.         global = Math.max(local,global);  
  10.     }  
  11.     return global;  
  12. }  
这道题虽然比较简单,但是用到的动态规划方法非常的典型,我们在以后的题目中还会遇到,大家还是要深入理解一下哈。我现在记得的用到的题目是 Jump Game ,以后有统计一下再继续更新。

 

 

 

教程参考:屈婉玲的youtube视频

 
以下为原创:
 
我的风格写法(使用javascript):
function FindGreatestSumOfSubArray(array)
{
    // write code here
    var tempMax = array[0],max = array[0];
    for(var i=1;i<array.length;i++){
        max = Math.max(max+array[i],array[i]);
        if(max>tempMax){
            tempMax = max;
        }
    }
    return tempMax;
}

很少用Math.max的形式,更多用if,因为Math.max只能用于单条语句。

第一次写的时候,使用

 

function FindGreatestSumOfSubArray(array)
{
    // write code here
    var tempMax = 0,max = 0;
    for(var i=0;i<array.length;i++){
        max = Math.max(max+array[i],array[i]);
        if(max>tempMax){
            tempMax = max;
        }
    }
    return tempMax;
}


因为数组元素不一定全是正数,所以这里设置tempMax = 0,max = 0;作为最小值是不对的。应该设置tempMax = array[0],max = array[0];

 

 

 

相同类型的题目:

Jump Game -- LeetCode

 

 

原题链接: http://oj.leetcode.com/problems/jump-game/ 

这道题是动态规划的题目,所用到的方法跟是在Maximum Subarray中介绍的套路,用“局部最优和全局最优解法”。我们维护一个到目前为止能跳到的最远距离,以及从当前一步出发能跳到的最远距离。局部最优local=A[i]+i,而全局最优则是global=Math.max(global, local)。递推式出来了,代码就比较容易实现了。因为只需要一次遍历时间复杂度是O(n),而空间上是O(1)。代码如下: 

[java]  view plain  copy
  1. public boolean canJump(int[] A) {  
  2.     if(A==null || A.length==0)  
  3.         return false;  
  4.     int reach = 0;  
  5.     for(int i=0;i<=reach&&i<A.length;i++)  
  6.     {  
  7.         reach = Math.max(A[i]+i,reach);  
  8.     }  
  9.     if(reach<A.length-1)  
  10.         return false;  
  11.     return true;  
  12. }  

这也是一道比较经典的动态规划的题目,不过不同的切入点可能会得到不同复杂度的算法,比如如果维护的历史信息是某一步是否能够到达,那么每一次需要维护当前变量的时候就需要遍历前面的所有元素,那么总的时间复杂度就会是O(n^2)。所以同样是动态规划,有时候也会有不同的角度,不同效率的解法。这道题目还有一个扩展Jump Game II,有兴趣的朋友可以看看。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值