【LeetCode】面试题42. 连续子数组的最大和(JAVA)

原题地址:https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/

题目描述:
【LeetCode】面试题42. 连续子数组的最大和(JAVA)_第1张图片
解题方案:
可以用动态规划来解。dp[i]表示以i为结尾的子数组的和的最大值。状态转移公式为
d p [ i ] = { d p [ i − 1 ] + n u m s [ i ] if  d p [ i − 1 ] > 0 n u m s [ i ] if  d p [ i − 1 ] < = 0 dp[i] = \begin{cases} dp[i-1]+nums[i] &\text{if } dp[i-1]>0 \\ nums[i] &\text{if } dp[i-1]<=0 \end{cases} dp[i]={dp[i1]+nums[i]nums[i]if dp[i1]>0if dp[i1]<=0
但由于我们只需要取整个数组中最大的数,所以不需要存储整个数组,只用一个变量保存即可。

代码:

动态规划:

class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        if(n == 0) return 0;
        int dp = nums[0];
        int max = dp;
        for(int i = 1; i <= n - 1; i ++)
        {
            if(dp > 0)
                dp = dp + nums[i];
            else
                dp = nums[i];
            max = dp > max ? dp : max;
        }
        return max;

    }
}

分治:
还可以用分治法解题,即分别考虑和最大的部分在左半边,右半边和跨越中点。左右半边继续递归,跨越中点处理为分别计算左右半边子数组和的最大值,再作和。

class Solution {
    public int maxSubArray(int[] nums) {
        return helper(0, nums.length - 1, nums);
    }
    int helper(int left, int right, int[] nums)
    {
        if(left == right) return nums[left]; //只剩一个值,返回
        int mid = (left + right) / 2;
        //左右半边和跨越中点值作比较
        return Math.max(helper(left, mid, nums), Math.max(helper(mid + 1, right, nums), crossSum(left, right, mid, nums))); 
    }
    int crossSum(int left, int right, int mid, int[] nums)
    {
        int leftSum = Integer.MIN_VALUE, rightSum = Integer.MIN_VALUE;
        int tmpSum = 0;
        // 计算左半子和
        for(int i = mid; i >= left; i --)
        {
            tmpSum += nums[i];
            leftSum = Math.max(tmpSum, leftSum);
        }
        tmpSum = 0;
        // 计算右半子和
        for(int j = mid + 1; j <= right; j ++)
        {
            tmpSum += nums[j];
            rightSum = Math.max(tmpSum, rightSum);
        }
        return leftSum + rightSum;
    }
}

你可能感兴趣的:(Leetcode)