13-53. 最大子序和

题目描述:
13-53. 最大子序和
解题思路:

可以使用动态规划或者分治算法

  • 动态规划

    • 对于求最大自序和,我们可以使用arr[i]来记录以下标 i 结尾的最大子序和,用一维数组来表示;

    • 则有arr[i] = max(arr[i-1]+arr[i],arr[i]);即要么该arr[i]单独成一段,要么和前面arr[i-1]共同组成一段。

    • 可写出方程
      $$
      f(i) = max(f(i-1)+arr[i],arr[i])
      $$
      则可以看出f(i)只和f(i-1)有关,因此可以使用一个变量pre用于记录当前i下的f(i-1),用maxVal记录当前i下的最大子序和。

    • 时间复杂度是O(n)

  • 分而治之

    • 可以将该数组划分为左右两个部分,每次都以其中间m为界限划分,[l,m] [m+1,r]

    • 划分成两部分之后,再进行合并,我们要维护四个变量:

      • lSum:以左端点的最大子序和
      • rSum:以右端点的最大子序和
      • mSum:任意端点的最大子序和
      • iSum:整个区间的和
    • 在合并时,要维护的这四个变量

      对于iSum最好维护,区间 [l,r]的iSum 就等于「左子区间」的iSum 加上「右子区间」的 iSum。

      对于 [l,r]的lSum,存在两种可能,它要么等于「左子区间」的lSum,要么等于「左子区间」的iSum 加上「右子区间」的 lSum,二者取大。

      rSum和lSum类似

      对于mSum;我们可以考虑 [l,r]的 mSum 对应的区间是否跨越 m——它可能不跨越 m,也就是说 [l,r] 的 mSum 可能是「左子区间」的mSum 和 「右子区间」的 mSum 中的一个;它也可能跨越 m,可能是「左子区间」的 }rSum 和 「右子区间」的lSum 求和。三者取大。

代码:

//动态规划
class Solution {
    public int maxSubArray(int[] nums) {
        int pre = 0;
        int maxVal = nums[0];
        for(int i = 0;i < nums.length;i++){
            pre = Math.max(pre + nums[i],nums[i]);
            maxVal = Math.max(maxVal,pre);
        }
        return maxVal;
    }
}
//分而治之:
class Solution {

    public class Status{
        public int lSum;
        public int rSum;
        public int mSum;
        public int iSum;
        public Status(){};
        public Status(int lSum,int rSum,int mSum,int iSum){
            this.lSum = lSum;
            this.rSum = rSum;
            this.mSum = mSum;
            this.iSum = iSum;
        }
    }
    public Status divide(int l,int r,int[] nums){
        if(l == r){
            return new Status(nums[l],nums[l],nums[l],nums[l]);
        }
        int m = (l + r) >> 1;
        Status lSub = divide(l,m,nums);
        Status rSub = divide(m+1,r,nums);
        return merge(lSub,rSub);

    }

    public Status merge(Status lSub,Status rSub){
        int lSum = Math.max(lSub.lSum,lSub.iSum+rSub.lSum);
        int rSum = Math.max(rSub.rSum,rSub.iSum+lSub.rSum);
        int mSum = Math.max(Math.max(rSub.mSum,lSub.mSum),lSub.rSum + rSub.lSum);
        int iSum = lSub.iSum + rSub.iSum;
        return new Status(lSum,rSum,mSum,iSum);
    }

    public int maxSubArray(int[] nums) {
        return divide(0,nums.length-1,nums).mSum;
    }
}
上一篇:53.函数的返回值


下一篇:53