不同于普通的数组最大子序列和,一条状态迁移方程就能搞定所有,环形子序列增加了更多最优值的可能,如序列[5,-3,5],如果是前者,最大值就是7,如果是前后两端序列可以相连,那么最大值应该是10
思路一
其实我们可以将问题划分成两种情况
1.一种是普通类型的连续的最大子序列和,根据dp[i]=nums[i]>0?dp[i-1]+nums[i]:nums[i],其中dp[i]为以第i个元素结尾的子序列最大值,如此遍历一遍数组,不断地更新dp[i]同时更新最优值ans,这样遍历一遍数组下来,连续一段的最大子序列和为ans,这种求解一段连续子序列最大值的动态规划算法也叫Kadane 算法
2.第二种是首尾相接的情况,即数组分成3个连续区间,我们要求的是第一个和第三个区间所有元素的和,令T[i,j]为以i为第一区间结尾下标、以j为第三区间开始下标的序列和,T[i,j]=nums[0,i]+nums[j,length-1],其中i+1<j
3.要获取T[i,j]的最大值,我们进一步修改T[i,j]的表达式
T[i,j]=nums[0,i]+rightmax[j,length-1];
Rightmax[j,length-1]=max{nums[j,length-1],Rightmax[j+1,length-1]} i+1<j<length-2
4.最后只需要比较前者的ans和后者的ans即可获得最大值
我的代码:
class Solution {
public:
int maxSubarraySumCircular(vector<int>& nums) {
int length=nums.size();
int last=nums[0];
int ans=last;
for(int i=1;i<length;i++)
{
if(last>0)
{
last=last+nums[i];
}
else
{
last=nums[i];
}
ans=ans>last?ans:last;
}
int *right=new int[length];
right[length-1]=nums[length-1];
for(int i=length-2;i>0;i--)
{
right[i]=right[i+1]+nums[i];
}
int *right_max=new int[length];
right_max[length-1]=nums[length-1];
for(int i=length-2;i>0;i--)
{
right_max[i]=right[i]>right_max[i+1]?right[i]:right_max[i+1];
}
int left=0;
for(int i=0;i<length-2;i++)
{
left+=nums[i];
if(left+right_max[i+2]>ans)
ans=left+right_max[i+2];
}
return ans;
}
};
思路二
1.同样的,我们还是要将问题求解划分为2部分,比较一段连续的情况和两段分开的情况
2.对于连续的一段的情况和思路一一样求解,这里就不再展开叙述。
3.对于两段分开的情况,我们可以采用逆向思路的方式求解,要求T[i,j]=nums[0,i]+nums[j,length-1]的最大值,即求T[i,j]=S-sum[i+1,j-1]的最大值,其中S为序列的总和而sum[i,j]为元素i到元素j的总和,这样就转化成了求解序列|i+1,j-1|的小值,使用Kadane算法即可求解最小连续子序列和
4.最后比较两种情况的最大值即可求解
我的代码:
class Solution {
public:
int getminmax(vector<int>& nums,int start,int end,int sort_type)
{
if(start>end)
return 0;
int ans=nums[start];
int last=nums[start];
for(int i=start+1;i<=end;i++)
{
if(sort_type==0)
{
last=last<0?last+nums[i]:nums[i];
ans=last<ans?last:ans;
}
else
{
last=last>0?last+nums[i]:nums[i];
ans=last>ans?last:ans;
}
}
return ans;
}
int maxSubarraySumCircular(vector<int>& nums) {
int length=nums.size();
int ans=getminmax(nums,0,length-1,1);
int total=0;
for(int i=0;i<length;i++)
{
total+=nums[i];
}
int ans1=total-getminmax(nums,1,length-2,0);
return ans>ans1?ans:ans1;
}
};