问题:给定一个数组A[0,…,n],求A的连续子数组,使得数组和最大。
穷举尝试所有可能,时间复杂度O(n^3)
int MaxSubsequenceSum(const int A[],int N)
{
int ThisSum, MaxSum, i, j, k;
MaxSum = 0;
for ( i=0; i<N; i++ )
for ( j=i; j<N; j++ )
{
ThisSum = 0;
for ( k=i; k<=j; k++ )
ThisSum += A[k];
if (ThisSum > MaxSum )
MaxSum = ThisSum;
}
return MaxSum;
}
最内层循环可根据如下式子做改进,去掉,可得到第二种方法。
也是穷举,时间复杂度O(n^2)。
int MaxSubSequenceSum( const int A[], int N )
{
int ThisSum, MaxSum, i, j;
MaxSum = 0;
for ( i=0; i<N; i++ )
{
ThisSum = 0;
for ( j=i; j<N; j++ )
{
ThisSum += A[j];
if ( ThisSum > MaxSum )
MaxSum = ThisSum;
}
}
return MaxSum;
}
采用分治策略,将给定序列分成前后两半,则最大子序列可能有3种情况:1,出现在前半部;2,出现在后半部;3,跨越前后半部。而第三种情况可以的最大和,可以通过求出前半部分的最大和(包含前半部分最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素)而得到,然后将这两个和相加。时间复杂度O(nlogn)。
static int MaxSubSum( const int A[], int Left, int Right)
{
int MaxLeftSum, MaxRightSum;
int MaxLeftBorderSum, MaxRightBorderSum;
int Center, i;
if (Left == Right)
if ( A[Left] > 0)
return A[Left];
else
return 0;
Center = ( Left + Right ) / 2;
MaxLeftSum = MaxSubSum( A, Left, Center );
MaxRightSum = MaxSubSum( A, Center + 1; Right );
MaxLeftBorderSum = 0;
LeftBorderSum = 0;
for( i=Center; i>=Left; i-- )
{
LeftBorderSum += A[i];
if ( LeftBorderSum > MaxLeftBorderSum )
MaxLeftBorderSum = LeftBorderSum;
}
MaxRightBorderSum = 0;
RightBorderSum = 0;
for( i=Center; i<=Right; i++ )
{
RightBorderSum += A[i];
if ( RightBorderSum > MaxRightBorderSum )
MaxRightBorderSum = RightBorderSum;
}
return GetMax( MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );
}
int MaxSubsequenceSum( const int A[], int N )
{
return MaxSubSum( A, 0, N-1 );
}
记S[I]为以A[i]结尾的数组中和最大的子数组,则:
int MaxSubsequenceSum( const int A[], int N )
{
int ThisSum, MaxSum, j;
ThisSum = 0;
MaxSum = ThisSum;
for ( j=0; j<N; j++ )
{
if(ThisSum > 0)
ThisSum += a[i];
else
ThisSum = a[i];
if(MaxSum < ThisSum)
MaxSum = ThisSum;
}
return MaxSum;
}