时间复杂度太大,该算法不可取。
该时间复杂度为O(N),一般遇到为次复杂度的可以考虑改进算法,使其复杂度为O(logN),将会有大的改善。
分治法在每一层递归上都有三个步骤:
分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题;
合并:将各个子问题的解合并为原问题的解。
针对此问题,分析方法如下:
1、先一分为二:左边为4,-3,5,-2;右边为:-1,2,6,-2
2、对左边再一分为二:左边为4,-3;右边为5,-2。计算左边子序列大于0的值分别为4和1,取4;计算右边子序列大于0的值分别为5和3,取5
3、对左边(4,-3,5,-2)再进行合:连续子序列跨越分界线计算的大于0的值为4-3+5=6最大,再与4和5相比较,得出6为最大值。
4、对右边再一分为二:左边为-1,2;右边为6,-2。计算左边子序列大于0的值分别为2和1,取2;计算右边子序列大于0的值分别为6和4,取6
5、对右边(-1,2,6,-2)再进行合:连续子序列跨越分界线计算的大于0的值为2+6=8最大,再与2和6比较,得出8为最大值。
6、对整个序列(4,-3,5,-2,-1,2,6,-2)进行合:连续子序列跨越分界线计算的大于0的值为4-3+5-2-1+2+6=11最大,再与6和8比较,得出11最大。
7、整个序列采用先分再合逐步递归的方法得出最终结果为11
时间复杂度为上图已经给出的O(NlogN),针对本题,分治法依然不是最理想的算法。
在线处理的算法时间复杂度仅为O(N),是最好的算法。
上图是以上四种算法运行时间进行比较,明显可以看出第四种算法最为高效。
上述各程序代码如下:
- #include <stdio.h>
- #include <time.h>
- //算法1
- int MaxSubseqSum1(int A[], int N, int * s, int* e)
- {
- int ThisSum, MaxSum = 0;
- int i, j, k;
- for (i = 0; i < N; i++) /* i是子列左端位置 */
- {
- for (j = i; j < N; j++) /* j是子列右端位置 */
- {
- ThisSum = 0; /* ThisSum是从A[i]到A[j]的子列和 */
- for (k = i; k <= j; k++)
- {
- ThisSum += A[k];
- }
- if (ThisSum > MaxSum) /* 如果刚得到的这个子列和更大 */
- {
- MaxSum = ThisSum; /* 则更新结果 */
- *e = j;
- *s = i;
- }
- } /* j循环结束 */
- } /* i循环结束 */
- return MaxSum;
- }
- //算法2
- int MaxSubseqSum2(int A[], int N,int * s, int* e)
- {
- int ThisSum, MaxSum = 0;
- int i, j;
- *s = 0;
- *e = N;
- for (i = 0; i < N; i++) /* i是子列左端位置 */
- {
- ThisSum = 0; /* ThisSum是从A[i]到A[j]的子列和 */
- for (j = i; j < N; j++) /* j是子列右端位置 */
- {
- ThisSum += A[j]; /*对于相同的i,不同的j,只要在j-1次循环的基础上累加1项即可*/
- if (ThisSum > MaxSum) /* 如果刚得到的这个子列和更大 */
- {
- MaxSum = ThisSum; /* 则更新结果 */
- *e = j;
- *s = i;
- }
- } /* j循环结束 */
- } /* i循环结束 */
- return MaxSum;
- }
- //算法3
- int MaxSubseqSum3(int A[], int left, int right, int *s, int *e)
- {
- int i = 0, j = 0, sum = 0;
- int s1 = 0, s2 = 0, lefts = 0, rights = 0;
- int center, leftsum, rightsum;
- if (left == right)
- {
- if (A[left]>0)
- sum = A[left];
- else
- sum = 0;
- *s = left; *e = right;
- }
- else
- {
- center = (left + right) / 2; //划分
- leftsum = MaxSubseqSum3(A, left, center, s, e); //对应情况1,递归求解
- rightsum = MaxSubseqSum3(A, center + 1, right, s, e); //对应情况2,递归求解
- //求解s1
- for (i = center; i >= left; i--)
- {
- lefts +=A[i];
- if (lefts > s1)
- {
- *s = i;
- *e = center/2*2; //不清楚为啥是这样的
- s1 = lefts;
- }
- }
- //再求解s2
- for (j = center + 1; j <= right; j++)
- {
- rights = rights + A[j];
- if (rights > s2)
- {
- s2 = rights;
- *e = j;
- *s = (center+1)/2*2; //依然不清楚
- }
- }
- sum = s1 + s2; //计算情况3的最大子段和
- if (sum<leftsum)
- sum = leftsum;
- if (sum<rightsum)
- sum = rightsum;
- }
- return sum;
- }
- int MaxSubseqSum4(int A[], int N, int * s, int* e)
- {
- int ThisSum, MaxSum;
- int i;
- int ss = 0;
- ThisSum = MaxSum = 0;
- for (i = 0; i < N; i++)
- {
- ThisSum += A[i]; /* 向右累加 */
- if (ThisSum > MaxSum)
- {
- MaxSum = ThisSum; /* 发现更大和则更新当前结果 */
- *s = ss;
- *e = i;
- }
- else if (ThisSum < 0) /* 如果当前子列和为负 */
- {
- ThisSum = 0; /* 则不可能使后面的部分和增大,抛弃之 */
- ss = i+1;
- }
- }
- return MaxSum;
- }
- int main() {
- int a[] = { -10 ,1, 2, 3, 4, - 5, - 23, 3, 7, - 21 };
- int result,s,e,i;
- clock_t start, ended;
- double duration;
- const int COUNT = 100000;
- start = clock();
- for ( i = 0; i< COUNT; i++)
- result = MaxSubseqSum1(a, sizeof(a) / sizeof(a[0]), &s, &e);
- ended = clock();
- duration = (double)(ended - start) / CLK_TCK;
- printf("ticks1 = %lf\n",(double)(ended - start));
- printf("duration1 = %lf\n", duration);
- printf("start1=%d,ended1=%d result1 = %d\n", s,e,result);
- start = clock();
- for ( i = 0; i< COUNT; i++)
- result = MaxSubseqSum2(a, sizeof(a) / sizeof(a[0]), &s, &e);
- ended = clock();
- duration = (double)(ended - start) / CLK_TCK;
- printf("ticks2 = %lf\n", (double)(ended - start));
- printf("duration2 = %lf\n", duration);
- printf("start2=%d,ended2=%d result2 = %d\n", s, e, result);
- start = clock();
- for ( i = 0; i< COUNT; i++)
- result = MaxSubseqSum3(a, 0, sizeof(a) / sizeof(a[0]), &s, &e);
- ended = clock();
- duration = (double)(ended - start) / CLK_TCK;
- printf("ticks3 = %lf\n", (double)(ended - start));
- printf("duration3 = %lf\n", duration);
- printf("start3=%d,ended3=%d result3 = %d\n", s, e, result);
- start = clock();
- for ( i = 0; i< COUNT; i++)
- result = MaxSubseqSum4(a, sizeof(a) / sizeof(a[0]), &s, &e);
- ended = clock();
- duration = (double)(ended - start) / CLK_TCK;
- printf("ticks4 = %lf\n", (double)(ended - start));
- printf("duration4 = %lf\n", duration);
- printf("start4=%d,ended4=%d result4 = %d\n", s, e, result);
- return 0;
- }
程序运行结果如下(在VS2010环境下):
可以看出算法1最差,算法4在线处理最好。
下图所示是在VC++6.0下的运行结果:
其中算法3因为采用递归算法,空间复杂度太大,运行结果出现了错误。