题目链接: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; } };