> 文章列表 > 【剑指offer-C++】JZ85:连续子数组的最大和(二)

【剑指offer-C++】JZ85:连续子数组的最大和(二)

【剑指offer-C++】JZ85:连续子数组的最大和(二)

【剑指offer-C++】JZ85:连续子数组的最大和[二]

    • 题目描述
    • 解题思路

题目描述

描述:输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,找到一个具有最大和的连续子数组。

1.子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组;
2.如果存在多个最大和的连续子数组,那么返回其中长度最长的,该题数据保证这个最长的只存在一个;
3.该题定义的子数组的最小长度为1,不存在为空的子数组,即不存在[]是某个数组的子数组;
4.返回的数组不计入空间复杂度计算;

数据范围:1<=n<=105,−100<=a[i]<=100。

要求:时间复杂度O(n),空间复杂度O(n)。

进阶:时间复杂度O(n),空间复杂度O(1)。

输入:[1,-2,3,10,-4,7,2,-5]
返回值:[3,10,-4,7,2]
说明:经分析可知,输入数组的子数组[3,10,-4,7,2]可以求得最大和为18,故返回[3,10,-4,7,2] 
输入:[1]
返回值:[1]
输入:[1,2,-3,4,-1,1,-3,2]
返回值:[1,2,-3,4,-1,1]
说明:经分析可知,最大子数组的和为4,有[4],[4,-1,1],[1,2,-3,4],[1,2,-3,4,-1,1],故返回其中长度最长的[1,2,-3,4,-1,1]  
输入:[-2,-1]
返回值:[-1]
说明:子数组最小长度为1,故返回[-1]  

解题思路

连续子数组的最大和(二):最直观的想法是,相对于(一)其区别在于要记录区间起始位置和结束位置,并且相同最大和的情况下返回长度最长的数组,而(一)中我们使用的是dp[i]表示以下标i为结尾的连续子数组的最大和,其递推公式为dp[i]= max(dp[i-1]+array[i],array[i])。那么怎么办呢?我们可以使用start和end分别表示当前区间起始位置和结束位置,初始均为0,maxs和maxe分别表示最大和区间起始位置和结束位置,初始也均为0,dp[0]初始化为第一个元素值,使用maxres表示最大和,初始为第一个元素值。与(一)的区别在于,每次循环遍历i时记录结束位置end为i,使用公式更新完dp[i]后,如果dp[i-1]+array[i]小于array[i],那么就更新起始位置为i,同时当dp[i]大于maxres或者dp[i]等于maxres且区间长度更大时,则更新最长区间以及最大值。最后将[maxs,maxe]区间的数值加入到结果数组中即可。

vector<int> FindGreatestSumOfSubArray(vector<int>& array) 
{int n=array.size();// dp[i]表示已i为结尾的连续子数组 dp[i]=max(dp[i-1]+array[i],array[i])vector<int> dp(n,0);// 此处要求有多个的话返回最长的 故要记录起始和结束int start=0,end=0; //最初区间为第一个元素dp[0]=array[0];int maxres=array[0]; //记录最大区间和为第一个元素int maxs=0,maxe=0; //最初区间为第一个元素for(int i=1;i<n;i++){end=i; //结束位置为idp[i]=max(dp[i-1]+array[i],array[i]);// 更新起始位置if(dp[i-1]+array[i]<array[i])start=i;// 更新最长区间以及最大值if(dp[i]>maxres||(dp[i]==maxres && end-start+1 > maxe-maxs+1)){maxe=end;maxs=start;maxres=dp[i];}}vector<int> res;for(int i=maxs;i<=maxe;i++)res.push_back(array[i]);return res;
}