其他分享
首页 > 其他分享> > leetcode 918环形最大子序列和

leetcode 918环形最大子序列和

作者:互联网

不同于普通的数组最大子序列和,一条状态迁移方程就能搞定所有,环形子序列增加了更多最优值的可能,如序列[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;
    }
};

标签:right,last,nums,int,环形,length,918,ans,leetcode
来源: https://blog.csdn.net/CJMINGMING/article/details/119059060