面试题 16.17. 连续数列
给定一个整数数组,找出总和最大的连续数列,并返回总和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
题解:
对于本题,我们可以先细细考虑一下题目,题目上说让我们找出总和最大的连续数列,再返回其总和。
既然如此,如果设i为0~numSize中的某个数(i可以从0一直增加到numsize),我们将数组以i下标结尾的最大连续子序列都求出来,最后再进行一次max比较即可。因为最大连续子序列一定是以0
~numsize的一个下标作为结尾元素的。
且对于数列中的任意一个数,其有两种可能:
1.在形成子列的过程中与前面连一块。
2.不与前面相连。
即:
每一个数据都有两个选择,与前面相连或者自己白手起家。
所以可知以i为结束元素下标是有两种可能性的,我们先进行一次max把大的选出来即满足了我们的“以i结尾的 最大 连续子序列”
所以我们可以列出状态转移方程:
dp[i]表示以i结尾的最大连续子序列
dp[i] = max(dp[i - 1] + nums[i],nums[i]);
并且我们不需要将所有的以i结尾的最大连续子列都求出来,求出来两个我们就比较一下舍弃一个即可。
附:
代码中:dp[i]=Max(dp[i-1]+nums[i],nums[i]);//此即为判断一下哪种情况下以i作为结束元素下标最“好”。
代码中:max=Max(dp[i],max);//自然此时以i为结束元素下标并不一定是最好的,可能不以i作为结束下标更好,于是来了一个比较。
代码
int Max(int x,int y)
{
return x>y?x:y;
}
int maxSubArray(int* nums, int numsSize){
if(numsSize==0)
return 0;
int dp[numsSize];
dp[0]=nums[0];
int max = dp[0];
for(int i=1;i<numsSize;i++)
{
dp[i]=Max(dp[i-1]+nums[i],nums[i]);//此即为判断一下哪种情况下以i作为结束元素下标最“好”
max=Max(dp[i],max);//自然此时以i为结束元素下标并不一定是最好的,
//可能不以i作为结束下标更好,于是来了一个比较
}
return max;
}
当然或许会有另一种设法,即我们设dp[i]为有i个数时其最大子序列的大小。
这样类似的我们可以得到下列代码:
int max(int a,int b,int c)
{
int temp = a>b?a:b;
return temp>c?temp:c;
}
int maxSubArray(int* nums, int numsSize){
if(numsSize==0)
return 0;
int dp[numsSize+1];
dp[1]=nums[0];
for(int i=2;i<=numsSize;i++)
{
dp[i]=max(dp[i-1]+nums[i-1],nums[i-1],dp[i-1]);//会出现不连续的情况
}
return dp[numsSize];
}
但我们会发现不对的地方,即由于我们的dp[i]只是代表有i个数时其最大子序列的大小,并不是一定包含第i个数,因此代码中的dp[i-1]+nums[i-1]此时就不一定是连续的了。所以不可这样写。而我们先前那个之所以可以是因为我们定义了以下标i为结尾了,所以一定连续。
当然啦,老规矩,能动态规划便可以使用滚动数组来进行优化~
代码:
int Max(int x,int y)
{
return x>y?x:y;
}
int maxSubArray(int* nums, int numsSize){
if(numsSize==0)
return 0;
int first,second;
first=nums[0];
int max = first;
for(int i=1;i<numsSize;i++)
{
second=Max(first+nums[i],nums[i]);
max=Max(second,max);
first=second;
}
return max;
}