LeetCode 689. Maximum Sum of 3 Non-Overlapping Subarrays

题目链接:https://leetcode.com/problems/maximum-sum-of-3-non-overlapping-subarrays/

题意:已知一个数组nums,以及一个整数k,找出数组中3个不交叉的长度为k的子数组,这三个数组的和最大,返回这三个数组的起始下标。其中$1<=nums.length<=20000$,$1<=nums[i]<=65536$,$1<=k<=floor(nums.length / 3)$

如果只寻找一个长度为k的子数组,令dp[i][0]表示在0-i之间存在一个最大的子数组和的大小,对于第i个数,要么在子数组中,要么不在子数组中,则$dp[i][0]=max(dp[i-1][0],dp[i-k][0]+nums[i-k+1]+...+nums[i])$

同理,如果只寻找2个长度为k的子数组,令dp[i][1]表示在0-i之间存在2个最大的子数组和的大小,则$dp[i][1]=max(dp[i-1][1],dp[i-k][0]+nums[i-k+1]+...+nums[i])$

对于三个子数组也一样:$dp[i][2]=max(dp[i-1][2],dp[i-k][1]+nums[i-k+1]+...+nums[i])$

因此从1个子数组开始即可推出3个子数组的情

最后还有一个问题,已经求出了$dp[i][2]$,如何求出每个子数组的位置呢?观察到所有元素都是正值,因此$dp[i-1][2]<=dp[i][2]$,因此可以从后向前找,当$dp[i-1][2]<dp[i][2]$时,说明长度为i时,第i个元素到第i-k+1个元素一定是其中一个子数组,一直向前找即可。

class Solution {
public:
    vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
        vector<int> ans;
        int **dp = new int *[nums.size()+1];
        int *s= new int[nums.size()+1];
        s[0]=0;
        for(int i=1;i<=nums.size();i++)   //前缀和
            s[i]=s[i-1]+nums[i-1];
        for(int i=0;i<=nums.size();i++){
            dp[i] = new int[3];
        }
        dp[0][0]=dp[0][1]=dp[0][2]=0;
        for(int i=k;i<=nums.size();i++){
            dp[i][0]=max(dp[i-1][0],s[i]-s[i-k]);
            dp[i][1]=max(dp[i-1][1],dp[i-k][0]+s[i]-s[i-k]);
            dp[i][2]=max(dp[i-1][2],dp[i-k][1]+s[i]-s[i-k]);
        }
        int i=nums.size();
        for(int j=2;j>=0;j--)
            for(;i>=1;i--)
                if(dp[i][j]>dp[i-1][j]){   
                    ans.push_back(i-k);  //nums[i-k]对应dp[i-k+1]
                    i=i-k;  //跳过k个元素
                    break;
            }
        reverse(ans.begin(),ans.end());
        return ans;
    }
};

  

posted @ 2019-06-02 09:08  dlutjwh  阅读(119)  评论(0编辑  收藏  举报