0.分治永远大于顺序?关于最大子序列和问题的思考
p17. 2.4.3 最大子序列和的问题的解
题目:给定整数A1,A2,......,AN,求∑k=i~jAk的最大值(如果所有整数都为负数,则最大子序列和为0)
书中给出了四种不同的算法,时间复杂度依次降低,下面我简单描述一下这四种算法
第一种:穷举法
求出所有子序列和,比较得出最大的
最简单想到的代码,效率十分低下,原因是没有利用数列的连贯性,对数列元素反复检索造成浪费
三层嵌套循环,时间复杂度
T(N)=O(N3)
int Maxsubsum(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++) /*开始按照确定的元素个数选出数列并计算子列和,较大者覆盖Maxsum,较小者在ThisSum中被丢弃*/ ThisSum += A[k]; if(ThisSum>Maxsum) Maxsum=ThisSum; } return Maxsum; }
第二种:改良后的穷举法
顾名思义,这种方法对方法一进行了改良.
当第选定了子序列的首项后,无需对子序列长度进行再次分组,直接顺序列出所有该首项下的子数列即可,减去了一次循环。
实际上换汤不换药
时间复杂度依旧为幂函数级
T(N)=O(N2)
int Maxsubsum(const int A[],int N) { int ThisSum,Maxsum,i,j,k; Maxsum=0; for(i=0;i<N;i++)//确定各个子序列的首项 { ThisSum=0; for(k=i;k<=j;k++)/*开始按照确定的元素个数选出数列并计算子列和,较大者覆盖Maxsum,较小者在ThisSum中被丢弃*/ { ThisSum += A[k]; if(ThisSum>Maxsum) Maxsum=ThisSum; } } return Maxsum; }
第三种:分治法
先上代码。
1 #include "stdio.h" 2 int 3 MaxSubSum(const int A[],int left,int right)//left,right分别为数列数组第一个元素和最后一个元素的下标 4 { 5 int Maxleftsum,Maxrightsum; 6 int Maxleftbordersum,Maxrightbordersum; 7 int leftbordersum,rightbordersum; 8 int Center,i; 9 10 if(left==right) /*base case*/ 11 if(A[left]>0) 12 return A[left]; 13 else 14 return 0; 15 16 17 Center=(left+right)/2; 18 Maxleftsum=MaxSubSum(A,left,Center); 19 Maxrightsum=MaxSubSum(A,Center+1,right); 20 21 Maxleftbordersum=0;leftbordersum=0; 22 for(i=Center;i>=left;i--) 23 { 24 leftbordersum +=A[i] 25 if(leftbordersum>Maxleftbordersum) 26 Maxleftbordersum=leftbordersum; 27 } 28 29 Maxrightbordersum=0;rightbordersum=0; 30 for(i=Center+1;i<=right;i++) 31 { 32 rightbordersum +=A[i] 33 if(rightbordersum>Maxrightbordersum) 34 Maxrightbordersum=rightbordersum; 35 } 36 37 return Max(Maxleftbordersum,Maxrightbordersum,Maxrightbordersum+Maxleftbordersum) 38 39 }
看起来可能有些复杂哈,我第一次看也是半天看不懂,没有这方面的基础。
分治法留到未来再写好了(因为我现在也没有掌握😂😂😂),只需要知道这种算法虽然写起来很复杂,但很高效
时间复杂度为
T(N)=O(N*LogN)
第四种:
//本算法将时间复杂度缩减至T(N)=O(N),未用到分治算法T(N)=O(NlogN),但是代码精简,也是一种高速的解题方法 //传统理解使用穷举列出所有序列T(N)=O(N^3),十分臃肿 #include <stdio.h> int max_son(int a[],int N){ int tempmax=0; int realmax=0; for (int i = 0; i < N; ++i) { tempmax+=a[i]; if(tempmax>realmax) realmax=tempmax; if(tempmax<0) tempmax=0; } return realmax; } int main(int argc, char const *argv[]) { int N; printf("how many numbers in your array?\n"); scanf("%d",&N); printf("please enter them in\n"); int a[N]; for (int i = 0; i < N; ++i) { scanf("%d",&a[i]); } printf("max son array's accumlization is %d\n",max_son(a,N) ); return 0; }
请读者自行理解其中奥妙,非常好理解,易读性也很高,时间复杂度也最低。
是这个问题最优解之一。
它有个名字,
“累积遍历算法”。
还有一个方法叫做动态规划,现在还未学到,未来再来填坑。
----------------------
Never afraid of failure