LeetCode 53. Maximum Subarray (Java)

题目:

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

解答

解答一:【动态规划】
分析遍历数组的情况。维持一个连续的数组元素和。
如果该数组的和大于0,那么加上一个元素之后的值肯定大于这个元素的值。即,从后一个元素开始的子数组和加上前面的数组会更大。
但是,如果当前的数组和是负数,加上后肯定没有从后一个元素开始的子数组的和大。
复杂度为O(n)

//利用变量sum来记录g(n-1)的值,通过g(n-1)和状态转移方程来求解出g(n),同时用变量max来记录g(n)的最大值即为f(n)
class Solution {
    public int maxSubArray(int[] nums) {
        int max=nums[0];
        int sum=nums[0];
        for(int i=1;i<nums.length;i++){
            if(sum<0){
                sum=nums[i];
            }
            else{
                sum+=nums[i];
            }
            if(sum>max){
                max=sum;
            }
        }
        return max;
    } 
}

解答二:【分治】
分治法:最大子串和的区间有以下三种情况(start,end分别为左右边界,mid为(start+end)/2):

(1) 区间完全在 A[start,mid-1]
(2) 区间完全在 A[mid+1,end]
(3) 区间包含有 A[mid]

按照这三种情况一直递归下去即可。
可根据递归关系式T(n)=2T(n/2)+n,计算出时间复杂度为O(logn)。【《算法导论》P51利用递归复杂树计算】
或可利用代数关系式计算

class Solution {
    public int maxSubArray(int[] nums) {
        return divide(nums,0,nums.length-1);
    }
    
    public int divide(int[] nums,int start,int end){
    //判断边界条件
        if(start==end)
            return nums[start];
        if(start==end-1)
            return Math.max(nums[start]+nums[end],Math.max(nums[start],nums[end]));
        int mid=(start+end)/2;
        int lmax=divide(nums,start,mid-1); //左边子问题的解
        int rmax=divide(nums,mid+1,end);//右边子问题的解
        int mmax=nums[mid];
        int sum=mmax;
        //寻找跨越中间值的解
        //计算中间值的左边
        for(int i=mid-1;i>=start;i--){
            sum+=nums[i];
            if(sum>mmax)
                mmax=sum;
        }
        sum=mmax;
        //计算中间值的右边
        for(int i=mid+1;i<=end;i++){
            sum+=nums[i];
            if(sum>mmax)
                mmax=sum;
        }
        return Math.max(mmax,Math.max(lmax,rmax));
    }
}

解析:

  1. 一个问题是该用递推、贪心、搜索还是动态规划,完全是由这个问题本身阶段间状态的转移方式决定的

    每个阶段只有一个状态->递推;
    每个阶段的最优状态都是由上一个阶段的最优状态得到的->贪心;
    每个阶段的最优状态是由之前所有阶段的状态的组合得到的->搜索;
    每个阶段的最优状态可以从之前某个阶段的某个或某些状态直接得到而不管之前这个状态是如何得到的->动态规划。

你可能感兴趣的:(LeetCode)