動態規劃_最大子陣列|||_1
假設給定陣列共有N個元素,需要找到K個不重合的子陣列使其和最大。令符號(i, j)表示在陣列前i個元素中找到j個不重合的和最大的子陣列的和,符號[a,b]表示在子陣列nums[a,a+1,...,b]中找到一個最大子陣列,返回最大子陣列的和。則有:
(i, j)=max{ (q, j),(p, j-1)+[p+1, i], 其中j<=q<=i-1,j-1<=p<=i-1}
下面以N=6,K=4為例具體說明.首先構建二維陣列dpk
(1,1)
(2,1) (2,2)
(3,1) (3,2) (3,3)
(4,2) (4,3) (4,4)
(5,3) (5,4)
(6,4)
(6,4)即為所求.根據(i, j)的表示式可以寫出:
(1,1)=nums[0];
(2,2)=(1,1)+[2,2];
(3,2)=max{(2,2),(2,1)+[3,3],(1,1)+[2,3]};
(4,2)=max{(2,2),(3,2),(3,1)+[4,4],(2,1)+[3,4],(1,1)+[2,4]};
(3,3)=(2,2)+[3,3];
(4,3)=max{(3,3),(3,2)+[4,4]
(5,3)=max{(3,3),(4,3),(4,2)+[5,5],(3,2)+[4,5],(2,2)+[3,5]};
觀察(2,2)與(3,2)的表示式可以發現:(2,2)=(1,1)+[2,2]<=(1,1)+[2,3],所以(3,2)的表示式可以改寫為:
(3,2)=max{(2,1)+[3,3],(1,1)+[2,3]};
同理可以改寫後面的表示式。基於此可以改寫(i, j)的表示式:
(i,
j)=max{ (p, j-1)+[p+1, i], 其中j-1<=p<=i-1}
觀察上述(1,1)到(5,3)的表示式發現,加粗部分重複出現,所以可以用一個二維陣列儲存[a,b]的值避免重複計算.
下面的程式碼中,過程maxBE(nums,beg,end,dp1)計算[beg,end],其中二維陣列dp1儲存[beg,end]的值避免重複計算
3. 【程式碼】
class Solution {
public:
/**
* @param nums: A list of integers
* @param k: An integer denote to find k non-overlapping subarrays
* @return: An integer denote the sum of max k non-overlapping subarrays
*/
int maxBE(vector<int> &nums,int beg,int end,vector<vector<int>> &dp1) {
if(dp1[beg+1][end+1]!=INT_MIN) {
return dp1[beg+1][end+1];
}
if(beg==end) {
dp1[beg+1][end+1]=nums[beg];
return dp1[beg+1][end+1];
}
int mid=beg+(end-beg)/2;
int i=mid-1,left=nums[mid],ls=left;
while(i>=beg) {
ls+=nums[i];
left=left>=ls?left:ls;
i--;
}
int j=mid+2,right=nums[mid+1],rs=right;
while(j<=end) {
rs+=nums[j];
right=right>=rs?right:rs;
j++;
}
int left_sum=maxBE(nums,beg,mid,dp1),mid_sum=left+right,right_sum=maxBE(nums,mid+1,end,dp1);
dp1[beg+1][end+1]=(left_sum>=right_sum?left_sum:right_sum)>=mid_sum?(left_sum>=right_sum?left_sum:right_sum):mid_sum;
return dp1[beg+1][end+1];
}
int maxSubArray(vector<int> nums, int k) {
// write your code here
int N=nums.size();
if(N==0||k<=0||N<k) {
return -1;
}
vector<vector<int>> dpk(N+1,vector<int>(k+1,INT_MIN));
vector<vector<int>> dp1(N+1,vector<int>(N+1,INT_MIN));
for(int i=1;i<=N+1-k;++i) {
dpk[i][1]=maxBE(nums,0,i-1,dp1);
}
for(int j=2;j<=k;++j) {
for(int i=j;i<=N+j-k;++i) {
for(int p=j-1;p<=i-1;++p) {
dpk[i][j]=dpk[i][j]>=(dpk[p][j-1]+maxBE(nums,p,i-1,dp1))?dpk[i][j]:(dpk[p][j-1]+maxBE(nums,p,i-1,dp1));
}//for
}//for
}//for
return dpk[N][k];
}
};