最大子列和问题(分治法和在线处理)


    时间复杂度太大,该算法不可取。


    

    该时间复杂度为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),是最好的算法。

上图是以上四种算法运行时间进行比较,明显可以看出第四种算法最为高效。


上述各程序代码如下:
  1. #include <stdio.h>
  2. #include <time.h>
  3. //算法1
  4. int MaxSubseqSum1(int A[], int N, int * s, int* e)
  5. {
  6. int ThisSum, MaxSum = 0;
  7. int i, j, k;
  8. for (i = 0; i < N; i++) /* i是子列左端位置 */
  9. for (j = i; j < N; j++) /* j是子列右端位置 */
  10. {
  11. ThisSum = 0; /* ThisSum是从A[i]到A[j]的子列和 */
  12. for (k = i; k <= j; k++) 
  13. {
  14. ThisSum += A[k];
  15. }
  16. if (ThisSum > MaxSum) /* 如果刚得到的这个子列和更大 */
  17. {
  18. MaxSum = ThisSum; /* 则更新结果 */
  19. *e = j;
  20. *s = i;
  21. }
  22. } /* j循环结束 */
  23. } /* i循环结束 */
  24. return MaxSum;
  25. }
  26. //算法2
  27. int MaxSubseqSum2(int A[], int N,int * s, int* e)
  28. {
  29. int ThisSum, MaxSum = 0;
  30. int i, j;
  31. *s = 0;
  32. *e = N;
  33. for (i = 0; i < N; i++) /* i是子列左端位置 */
  34. ThisSum = 0; /* ThisSum是从A[i]到A[j]的子列和 */
  35. for (j = i; j < N; j++) /* j是子列右端位置 */
  36. ThisSum += A[j];        /*对于相同的i,不同的j,只要在j-1次循环的基础上累加1项即可*/
  37. if (ThisSum > MaxSum)   /* 如果刚得到的这个子列和更大 */
  38. {
  39. MaxSum = ThisSum;   /* 则更新结果 */
  40. *e = j;
  41. *s = i;
  42. }
  43. } /* j循环结束 */
  44. } /* i循环结束 */
  45. return MaxSum;
  46. }
  47. //算法3
  48. int MaxSubseqSum3(int A[], int left, int right, int *s, int *e)
  49. {
  50. int i = 0, j = 0, sum = 0;
  51. int s1 = 0, s2 = 0, lefts = 0, rights = 0;
  52. int center, leftsum, rightsum;
  53. if (left == right)
  54. {
  55. if (A[left]>0)
  56. sum = A[left];
  57. else
  58. sum = 0;
  59. *s = left; *e = right;
  60. }
  61. else
  62. {
  63. center = (left + right) / 2;               //划分
  64. leftsum = MaxSubseqSum3(A, left, center, s, e);       //对应情况1,递归求解
  65. rightsum = MaxSubseqSum3(A, center + 1, right, s, e);      //对应情况2,递归求解
  66. //求解s1
  67. for (i = center; i >= left; i--)
  68. {
  69. lefts +=A[i];
  70. if (lefts > s1) 
  71. {
  72. *s = i;
  73. *e = center/2*2;   //不清楚为啥是这样的
  74. s1 = lefts;
  75. }
  76. }
  77. //再求解s2
  78. for (j = center + 1; j <= right; j++)
  79. {
  80. rights = rights + A[j];
  81. if (rights > s2) 
  82. {
  83. s2 = rights; 
  84. *e = j;
  85. *s = (center+1)/2*2; //依然不清楚
  86. }
  87. }
  88. sum = s1 + s2;                //计算情况3的最大子段和
  89. if (sum<leftsum)
  90. sum = leftsum;
  91. if (sum<rightsum)
  92. sum = rightsum;
  93. }
  94. return sum;
  95. }


  96. int MaxSubseqSum4(int A[], int N, int * s, int* e)
  97. {
  98. int ThisSum, MaxSum;
  99. int i;
  100. int ss = 0;
  101. ThisSum = MaxSum = 0;
  102. for (i = 0; i < N; i++) 
  103. {
  104. ThisSum += A[i]; /* 向右累加 */
  105. if (ThisSum > MaxSum)
  106. {
  107. MaxSum = ThisSum; /* 发现更大和则更新当前结果 */
  108. *s = ss;
  109. *e = i;
  110. }
  111. else if (ThisSum < 0) /* 如果当前子列和为负 */
  112. {
  113. ThisSum = 0; /* 则不可能使后面的部分和增大,抛弃之 */
  114. ss = i+1;
  115. }
  116. }
  117. return MaxSum;
  118. }
  119. int main() {
  120. int a[] = { -10 ,1, 2, 3, 4, - 5, - 23, 3, 7, - 21 };
  121. int result,s,e,i;
  122. clock_t start, ended;
  123. double duration;
  124. const int COUNT = 100000;
  125. start = clock();
  126. for ( i = 0; i< COUNT; i++)
  127. result = MaxSubseqSum1(a, sizeof(a) / sizeof(a[0]), &s, &e);
  128. ended = clock();
  129. duration = (double)(ended - start) / CLK_TCK;
  130. printf("ticks1    = %lf\n",(double)(ended - start));
  131. printf("duration1 = %lf\n", duration);
  132. printf("start1=%d,ended1=%d result1 = %d\n", s,e,result);
  133. start = clock();
  134. for ( i = 0; i< COUNT; i++)
  135. result = MaxSubseqSum2(a, sizeof(a) / sizeof(a[0]), &s, &e);
  136. ended = clock();
  137. duration = (double)(ended - start) / CLK_TCK;
  138. printf("ticks2    = %lf\n", (double)(ended - start));
  139. printf("duration2 = %lf\n", duration);
  140. printf("start2=%d,ended2=%d result2 = %d\n", s, e, result);
  141. start = clock();
  142. for ( i = 0; i< COUNT; i++)
  143. result = MaxSubseqSum3(a, 0, sizeof(a) / sizeof(a[0]), &s, &e);
  144. ended = clock();
  145. duration = (double)(ended - start) / CLK_TCK;
  146. printf("ticks3    = %lf\n", (double)(ended - start));
  147. printf("duration3 = %lf\n", duration);
  148. printf("start3=%d,ended3=%d result3 = %d\n", s, e, result);

  149. start = clock();
  150. for ( i = 0; i< COUNT; i++)
  151. result = MaxSubseqSum4(a, sizeof(a) / sizeof(a[0]), &s, &e);
  152. ended = clock();
  153. duration = (double)(ended - start) / CLK_TCK;
  154. printf("ticks4    = %lf\n", (double)(ended - start));
  155. printf("duration4 = %lf\n", duration);
  156. printf("start4=%d,ended4=%d result4 = %d\n", s, e, result);
  157. return 0;
  158. }
程序运行结果如下(在VS2010环境下):

可以看出算法1最差,算法4在线处理最好。
下图所示是在VC++6.0下的运行结果:

其中算法3因为采用递归算法,空间复杂度太大,运行结果出现了错误。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值