力扣LeetCode #53 最大子序和(MaxSubArray)

- 题目描述

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

来源:LeetCode

- 示例

输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

输入:[13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]
输出:43

- 思路分析

  • 方法1: 动态规划
    定义sum[i]:前i个数的最大和。在第i个数,我们有两种选择,一种选择是在sum[i-1]的基础上,加上nums[i],另一种选择是从nums[i]开始重新计算最大和。因此可以得出子结构:
    s u m [ i ] = m a x ( s u m [ i − 1 ] + n u m s [ i ] , n u m s [ i ] ) sum[i] = max(sum[i-1]+nums[i], nums[i]) sum[i]=max(sum[i1]+nums[i],nums[i])
  • 方法2:分治法
    为了得到整个数组的连续最大和,我们可以将其分成两部分,左半部分和右半部分。这样连续的最大和会在三种情况中产生:①所有数都在左半部分;;②所有数都在右半部分;③一部分数在左半部分,一部分数在右半部分。前两种情况递归就可以解决,第三种情况需要特殊处理。考虑第三种情况时,就从中间向两边出发,分别找到左半部分最大和以及右半部分最大和相加即可。

- JAVA实现

  • 方法1实现(O(n)空间复杂度)
public static int maxSubArray(int[] nums) {
    int len = nums.length, max = nums[0];
    int[] sum = new int[len];
    sum[0] = nums[0];
    for(int i=1; i<len; i++) {
        sum[i] = sum[i - 1] + nums[i] > nums[i] ? sum[i - 1] + nums[i] : nums[i];
        if(sum[i]>max) max = sum[i];
    }
    return max;
}
  • 方法1实现(O(1)空间复杂度)
public static int maxSubArray(int[] nums) {
    int len =nums.length, max = nums[0], sum = nums[0];
    for(int i=1;i<len;i++) {
        sum = sum+nums[i]>nums[i] ? sum+nums[i] : nums[i];
        if(sum>max) max = sum;
    }
    return max;
}
  • 方法2实现
public static int divideMaxSubArray(int[] nums, int start, int end) {
    int len = end-start;
    if(len == 1) return nums[start];   //base case
    int max_left, max_right, max_mid, max;
    max_left = divideMaxSubArray(nums, 0, len/2);
    max_right = divideMaxSubArray(nums, len/2, len);
    max_mid = acrossDivideMaxSubArray(nums, len/2-1, len/2);
    max = Math.max(max_left, max_right);
    max = Math.max(max_mid, max);
    return max;
}

public static int acrossDivideMaxSubArray(int[] nums, int mid_left, int mid_right) {
    int max_left = nums[mid_left], max_right = nums[mid_right];
    int sum = 0, len = nums.length;
    for(int i=mid_left;i>=0;i--) {
        sum += nums[i];
        max_left = sum>max_left ? sum : max_left;
    }
    sum = 0;
    for(int i=mid_right;i<len;i++) {
        sum += nums[i];
        max_right = sum>max_right ? sum : max_right;
    }
    return max_left+max_right;
}
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页