您的位置:首页 > 其它

微软100题第3题:求子数组的最大和

2015-06-26 16:23 381 查看


题目:输入一个整形数组,数组里有正数也有负数。

数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。

求所有子数组的和的最大值。要求时间复杂度为O(n)。

例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,

因此输出为该子数组的和18。


分析:该题也是Leetcode上面的题目,第53题。解题方法有多种, 本次用两种时间复杂度最低的方式实现。

方法1:动态规划O
,分析题目后,最大的连续子序列和从以当前元素pData[i]结尾的序列和中找,当前元素结尾的序列和为f(i).

f(i)= pData[i], i=0 or f(i-1)<=0; or f(i) = f(i-1)+pData[i], i!=0 and f(i-1)>0

取 MAX(f(i)), i>=0 and i<n;

int maxSubArray( vector<int> & nums )
{
int cursum=0, maxsum=nums[0];
for( vector<int>::size_type i=0; i!= nums.size(); i++ )
{
cursum += nums[i];
if( cursum > maxsum )
{
maxsum = cursum;
}
if(cursum <0)
cursum = 0;
}

return maxsum ;
}

方法2:使用“分而治之”策略,O[NlogN]。最大连续子序列和最可能出现在序列的3个地方, 只需取三个数据中最大的那个即可。

a. 数组的左半边;

b. 数组的右半边;

c. 跨越左右,中间的某一段区间。

前两种情况采用递归即可处理。

static int MaxSubSum( vector<int> & nums , int left, int right)
{
int mid=(left +right)/2, maxleft=0, maxright=0;
int leftsum=0, rightsum=0;
int maximum =0;

if(left == right)
{
//if(nums[left] >0)
return nums[left] ;
}
maxleft = MaxSubSum(nums, left, mid);
maxright = MaxSubSum(nums, mid+1, right);

if(maxleft>maxright)
maximum = maxleft;
else
maximum = maxright;

maxleft = nums[mid];
maxright = nums[mid+1];

for(int i=mid; i>=left; i--)
{
leftsum += nums[i];
if(leftsum > maxleft)
maxleft = leftsum;
}

for(int i= mid+1; i<=right; i++)
{
rightsum += nums[i];
if(rightsum > maxright)
maxright = rightsum;
}

return maximum = ((maxleft + maxright) > maximum)?(maxleft + maxright) : maximum;
}

int maxSubArray( vector<int> & nums )
{
return MaxSubSum(nums, 0, nums.size()-1);
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息