最大子数组和

最大子数组和

问题引入

在这里插入图片描述
在这里插入图片描述

解决思路

在这里插入图片描述

1.蛮力枚举 O(n^3)

在这里插入图片描述

在这里插入图片描述

代码实现

public static int MaxSubArray(int[] arr){
    int max = Integer.MIN_VALUE;
    for(int l = 0; l < arr.length; l++){
        for(int r = 0; r < arr.length; r++){
            int Slr = 0; // S(l,r) = 0
            for(int i = l; i <= r; i++){
                Slr = Slr + arr[i];
            }
            max = Math.max(max,Slr);
        }
    }
    return max;
}
2.优化枚举 O(n^2)

在这里插入图片描述

每次计算可以利用之前的计算结果,S (l , r) = S (l , r - 1) + arr [ r ]

public static int MaxSubArray(int[] arr){
    int max = Integer.MIN_VALUE;
    for(int l = 0; l < arr.length; l++){
        int S = 0;
        for(int r = l; r < arr.length; r++){
            S = S + arr[r];
            max = Math.max(max,S);
        }
    }
    return max;
}
3.分而治之 O(nlogn)

在这里插入图片描述

​ 重点在于怎样求解 S3 ,稍加分析可知,可将 S3 分为两左右部分进行计算,Left 是以 arr[mid] 结尾的最大子数组,Right 是以 arr[mid + 1] 开始的最大子数组。S3 = Left + Right。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码实现

public static int CrossingSubArray(int[] arr,int low,int high){
    int left = Integer.MIN_VALUE;
    int sum = 0;
    int mid = low + (high - low) / 2;
    for(i = mid; i >= low; i--){
        sum = sum + arr[i];
        left = Math.max(left,sum);
    }
    int right = Integer.MIN_VALUE;
    sum = 0;
    for(int i = mid + 1; i <= high; i++){
        sum = sum + arr[i];
        right = Math.max(right,sum);
    }
    int S_3 = left + right;
    return S_3;
}

算法实例

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码实现

public static int MaxSubArray(int[] arr,int low,int high){
    if(low == high){
        return arr[low];
    }
    int mid  = low + (high - low) / 2;
    int S_1 = MaxSubArray(arr,low,mid);
    int S_2 = MaxSubArray(arr,mid + 1,high);
    int S_3 = CrossingSubArray(arr,low,high);
    int S = Math.max(S_1,S_2);
    int S_max = Math.max(S,S_3);
    return S_max;
} 

在这里插入图片描述

在这里插入图片描述

4.动态规划 空间:O(n) 时间:O(n)

​ dp[i] 表示以 arr[i] 结尾的最大子数组的和,所以本题结果即为返回 dp 数组的最大值。

​ 状态转移方程:

// arr[i] 要么自成一派,要么和前边的数组合并
dp[i] = Math.max(arr[i], dp[i - 1] + arr[i]);

​ 代码实现:

public static int MaxSubArray(int[] arr){
    int n = arr.length;
    int[] dp = new int[n];
    dp[0] = arr[0];
    for(int i = 1; i < n; i++){
        dp[i] = Math.max(arr[i],dp[i - 1] + arr[i]);
    }
    int res = Integer.MIN_VALUE;
    for(int i = 0; i < n; i++){
        res = Math.max(res,dp[i]);
    }
    return res;
}
5.动态规划(压缩空间) 时间:O(n)

观察发现,我们最后只需返回最大子数组的最大值,而 dp 数组中其他值我们并不需要,所以我们不必为其申请一个长度为 n 的数组保存其值,只需定义两个变量循环调用,不断更新结果最大值即可。

public static int MaxSubArray(int[] arr){
    int n = arr.length;
    if(n == 0){
        return 0;
    }
    int dp_0 = arr[0];
    int dp_1 = 0;
    int res = dp_0;
    for(int i = 1; i < n; i++){
        dp_1 = Math.max(arr[i],dp_0 + arr[i]);
        dp_0 = dp_1;
        res = Math.max(res,dp_1);
    }
    return res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值