【三次过】Lintcode 42. 最大子数组 II

给定一个整数数组,找出两个 不重叠 子数组使得它们的和最大。
每个子数组的数字在数组中的位置应该是连续的。
返回最大的和。

样例

给出数组 [1, 3, -1, 2, -1, 2]
这两个子数组分别为 [1, 3] 和 [2, -1, 2] 或者 [1, 3, -1, 2] 和 [2],它们的最大和都是 7

挑战

要求时间复杂度为 O(n)

注意事项

子数组最少包含一个数


解题思路1:

既然在上一题Lintcode 41:Maximum Subarray已经可以求出整个数组的最大和子数组,那么这个题目就是增加了一条分界线,求分界线左右两边的子数组的最大和相加,很容易想到:遍历分界线,依次求取分界线两端的最大和。这样做的时间复杂度为O(n^2),代码如下:

public class Solution {
    /*
     * @param nums: A list of integers
     * @return: An integer denotes the sum of max two non-overlapping subarrays
     */
    public int maxTwoSubArrays(List<Integer> nums) {
        // write your code here
        int res = Integer.MIN_VALUE;
        int[] numss = new int[nums.size()];
        for(int i=0; i<nums.size(); i++)
            numss[i] = nums.get(i);
        
        for(int i = 1; i < numss.length; i++){
            int temp1 = maxSubArray(numss, 0, i-1);
            int temp2 = maxSubArray(numss, i, numss.length-1);
            
            res = Math.max(res, temp1+temp2);
        }
        
        return res;
    }
    
    //求nums[l...r]之间最大子数组和
    public int maxSubArray(int[] nums, int l, int r) {
        //dp[i]表示以i为结尾子数组的最大和
        int[] dp = new int[r-l+1];
        dp[0] = nums[l];
        
        int res = nums[l];
        
        for(int i=1; i<r-l+1; i++){
            dp[i] = Math.max(dp[i-1]+nums[l+i], nums[l+i]);
            res = Math.max(res, dp[i]);
        }
        
        return res;
    }
}

解题思路2:

同样是上面的思路,但是利用空间换时间的方式,先从左向右遍历,将左边子数组所有最大和保存在一个数组中,再从右向左遍历,将右边子数组所有最大和保存在另一个数组中,最后将两个数组彼此不相交的位置进行相加即可。这样做的时间复杂度为O(n).

class Solution {
public:
    /*
     * @param nums: A list of integers
     * @return: An integer denotes the sum of max two non-overlapping subarrays
     */
    int maxTwoSubArrays(vector<int> &nums) 
    {
        // write your code here
        vector<int> lRes(nums.size() , INT_MIN);
        lRes[0] = nums[0];
        int temp = nums[0];
        
        for(int i=1 ; i < nums.size() ; i++)
        {
            temp = max(temp+nums[i] , nums[i]);
            lRes[i] = max(temp , lRes[i-1]);
        }
        
        vector<int> rRes(nums.size() , INT_MIN);
        rRes[nums.size()-1] = nums[nums.size()-1];
        temp = nums[nums.size()-1];
        
        for(int i=nums.size()-2 ; i >=0 ;i--)
        {
            temp = max(temp+nums[i] , nums[i]);
            rRes[i] = max(temp , rRes[i-1]);
        }
        
        int res = INT_MIN;
        for(int i=0 ; i+1 < nums.size() ; i++)
        {
            int t = lRes[i] + rRes[i+1];
            
            res = res > t ? res : t;
        }
        
        return res;
    }
    
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值