vlambda博客
学习文章列表

动态规划(二)--连续子数组的最大和

来源:LeetCode

难度:简单

描述:

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。


示例1:


分析:该题要求咱们找出连续子数组的最大和,那么咱们可以直接枚举所有子数组,分别计算子数组和,找出最大的即可,但这个时间复杂度不符合要求...,咱们换种思路,由于题目要连续的子数组,那咱们只要计算出每个元素的最大子数组和,而所有元素子数组和中最大的便是解,以下是具体解法


解题


方法一:暴力法

思路:两层循环,枚举每个子数组,计算并保留大的子数组和


代码:

 1public int maxSubArray(int[] nums) {
2    int max = Integer.MIN_VALUE;
3    for(int i = 0;i < nums.length;i++){
4        int sum = 0;
5        //枚举所有子数组
6        for(int j = i;j < nums.length;j++){
7            //计算每个子数组和
8            sum += nums[j];
9            //保留最大值
10            if(sum > max) {
11                max = sum;
12            }
13        }
14    }
15    return max;
16}

时间复杂度:O(n2) 

空间复杂度:O(1)


方法二:动态规划法

思路:题目要求计算整个数组所能达到的最大连续子数组和,那么咱们只要计算出数组中每个元素所能得到的最大连续子数组和即可,挑选出其中最大的即是最后的解;

举个例子:假设数组一个元素,解即是该元素,如果有两个元素,解就是第一个元素的最大子数组和(本身)与第二个元素的最大子数组和(第二个元素本身与前一个元素最大子数组和加上第一个元素之间的最大值),由此咱们得到递推方程:dp[i] = Math.max(dp[i - 1] + arr[i ], arr[i])


代码:

 1public int maxSubArray(int[] nums) {
2    if (nums == null || nums.length == 0) {
3        return -1;
4    }
5    int[] dp = new int[nums.length];
6    dp[0] = nums[0];
7    int res = dp[0];
8    for (int i = 1; i < nums.length; i++) {
9        //计算每个元素所能得到的最大连续子数组和
10        dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
11        //保留最大的结果
12        res = Math.max(res, dp[i]);
13    }
14    return res;
15}

时间复杂度:O(n) 

空间复杂度:O(n)


继续优化:

思路:方法二中用dp数组来保存每个子数组的结果,其实咱们只用到了前一个元素的子数组和,那么只用一个元素保存前一个子数组和即可


代码:

 1public int maxSubArray(int[] nums) {
2    if (nums == null || nums.length == 0) {
3        return -1;
4    }
5    int dp = nums[0];
6    int res = dp;
7    for (int i = 1; i < nums.length; i++) {
8        //计算每个元素所能得到的最大连续子数组和
9        dp = Math.max(dp + nums[i], nums[i]);
10        //保留最大的结果
11        res = Math.max(res, dp);
12    }
13    return res;
14}

时间复杂度:O(n) 

空间复杂度:O(1)


以上仅是个人思路解法,觉得还不错欢迎点赞关注分享


往期精彩推荐