您的位置:首页 > 理论基础 > 数据结构算法

数据结构——最大子序列和

2018-03-17 19:26 381 查看
     最近我打算重温一遍数据结构,于是又遇到了求最大子序列和这一基本问题。记得之前我就没有明白透彻,这次便记录下来。     求最大子序列和,即求一个序列中,和值最大的连续子序列。首先采用暴力解法,即求出所有的子序列和,得到最大和,这个算法的时间复杂度是O(n^2)。
int MaxSubSum(int K, int a[])	//K是序列个数,用数组a存储
{//计算所有子序列的和 时间复杂度是O(n^2)
int preSub, maxSubSum = 0;
for (int i = 0; i < K; i++)
{
preSub = 0;
for (int j = i; j < K; j++)
{
preSub += a[j];
if (preSub > maxSubSum)
maxSubSum = preSub;
}
}
return maxSubSum;
}
    若是得到了时间复杂度O(n^2)的算法,我们得尝试优化到O(n*logn)。于是可以采用分治法,递归地解决这个问题——即把序列一分为二,分别递归求得左半边和右半边子序列最大和,再求出跨分界线子序列最大和,三者中的最大值即为所求,如下图所示:                                   

           

    为什么这个算法的时间复杂度是O(n*logn)呢?因为长度N的子序列需花费时间是                          T(N) = 2 * T(N/2) + cN        其中T(1) = O(1)        由此可推出,  T(N) = 2 * ( 2 * T(N/4) + c*N/2 ) + cN                                   = 4 * T(N/4) + 2cN                                ..                                ..                           T(N) = 2^n * O(1) + k*cN    其中 N / 2^k = 1    
                   即    T(N) = 2 ^n * O(1) + N*logN
    因此,分治法的时间复杂度是O(n*logn)。函数实现如下:
int Max3(int x, int y, int z)	//求三者中最大值
{
int max;
if (x > y) max = x;
else max = y;
if (z > max) max = z;
return max;
}
int DivideAndConquer(int a[], int left, int right)
{//分治法求数列 a[left]到 a[right]的最大子序列和
if (left == right)		//子列中只有一个数字,则递归终止
{
return a[left] > 0 ? a[left] : 0;
}
else
{
int centre = (left + right) / 2;			        //分界线
int maxLeftSum = DivideAndConquer(a, left, centre);		//递归求左序列最大和
int maxRightSum = DivideAndConquer(a, centre + 1, right);	//递归求右序列最大和
//下面求跨分界线的子序列最大和
int leftBorderSum = 0, rightBorderSum = 0;
int maxLeftBorderSum = 0, maxRightBorderSum = 0;
for (int i = centre; i >= left; i--)		//往左依次扫描
{
leftBorderSum += a[i];
if (leftBorderSum > maxLeftBorderSum) maxLeftBorderSum = leftBorderSum;
}
for (int i = centre + 1; i <= right; i++)	//往右依次扫描
{
rightBorderSum += a[i];
if (rightBorderSum > maxRightBorderSum) maxRightBorderSum = rightBorderSum;
}
return Max3(maxLeftSum, maxRightSum, maxLeft
9d10
BorderSum + maxRightBorderSum);
}
}
    最后,采用即时处理的算法,可以使时间复杂度降至O(n)。它的实现是:从输入的第一个数起,就进行累和,更新出现的最大和,若当前累和是负数,则弃之,从下一个数起重新累和。代码如下:
int MaxSubSum(int K)
{
int n, sum = 0, maxSum = 0;
for (int i = 0; i < K; i++)
{
cin >> n;				//输入一个数
sum += n;				//累和
if (sum < 0) sum = 0;	                //若当前序列和为负,则弃之
else if (sum > maxSum) maxSum = sum;	//更新最大和
}
return maxSum;
}
    至此,关于这道题的三种不同算法都介绍完了。通过此题,有助于我理解并分析时间复杂度,比较不同算法间的优劣。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: