//计算最大子列和,T(n)=O(n^2) #include <stdio.h> #include <stdlib.h> //一旦由i确定左端,thisSum就从左端往右加,加一个值更新一次thisSum //当第二个数作为左端时,thisSum要归0,因为这代表着第二种序列 int main() { int a[n]; int i,j; int maxSum=0,thisSum; for(i=0;i<n;i++)//i为左端 { thisSum=0; for(j=i;j<n;j++)//j为右端 { thisSum+=a[j]; if(thisSum > maSum) maxSum = thisSum; } } return 0; }
时间复杂度为O(N^2)
第二种算法:分治法,复杂度为O(N*logN)
分治的思想在于将数组分为左半部和右半部,且左右部相互独立,分别去求左半部和右半部的最大子列和
再求从中轴线开始,向左扫描,得MaxLeftBorderSum和MaxRightBorderSum,将他们加起来得到贯穿中轴线的子列和
最大子列和逃不出三个部分,所以max3(MaxLeftSum,MaxLeftBorderSum+MaxRightBorderSum)就是最大子列和
//分治法计算最大子列和,时间复杂度为T(N*logN) #include <stdio.h> #include <stdlib.h> int A[N]; int MaxSubSum(int A[],int left,int right) { int LeftSubSum,RightSubSum,LeftBorderSum=0,RightBorderSum=0; int center,MaxLeftBorderSum=0,MaxRightBordersum=0; if(left == right) { if(A[left] > 0) return A[left]; else return 0; } center=(right+left)/2; LeftSubSum=MaxSubSum(A,left,center); RightSubSum=MaxSubSum(A,center+1,right); for(i=center; i >= left; i--) { LeftBorderSum+=A[i]; if(LeftBorderSum > MaxleftBorderSum) MaxLeftBorderSum=LeftBorderSum; } for(i=center+1; i<=right; i++) { RightborderSum+=A[i]; if(RightBorderSum > MaxRightBorderSum) MaxRightBorderSum= RightBorderSum; } return max3(LeftSubSum,RightSubSum,MaxLeftBorderSum+MaxrightBorderSum); } int main() { return MaxSubSum(A,0,N-1); }
求左半部的最大子列和,就和求一整块的最大子列和一样,再分成左半部和右半部
每次递归,LeftBordersum/RightBordersum以及MaxBorderSum都从0开始
疑惑的是如果都是负数,最大子列和不就为0吗?
第三种算法:online algorithm(在线算法)
每次加一个到ThisSum,如果某次小于0,ThisSum归0,因为让这个负的ThisSum再往后加,只可能让当前加的这个数变小
所以,直接抛弃前面,从为正的开始
这个算法的正确性让我难以证明
//在线算法计算最大子列和,时间复杂度为T(N) #include <stdio.h> #include <stdlib.h> int SubSum(int A[]) { int ThisSum=0,Maxsum=0; for(i=0;i<n; i++) { ThisSum+=A[i]; if(ThisSum > MaxSum) MaxSum=ThisSum; if(ThisSum < 0) ThisSum=0; } } int main() { return SubSum(); }
第二种算法的时间复杂度分析:
T(n)=2T(n/2)+O(n)
把O(n)换成n(目前的知识不知道为什么,结论是不影响)
第一次:T(n)=2T(n/2)+n
让T(n/2)递推:T(n/2)=2T(n/2^2)+n/2
第二次:T(n)=2^2T(n/2^2)+2n
....
......
第k次:T(n)=2^k*T(n/2^k)+k*n
n/2^k最后会接近1,T(n/2^k)->T(1)=1
且n=2^k -> k==log2 n
-->T(n)=n+n*log n
《算法及数据分析(c)》中默认了n为偶数,我的理解是这样才能使n*logn>n,否则就不能说复杂度是O(n*logn)(因为复杂度总是选取较大的项)
且就算为奇数,分析要复杂些,解雇还是O(n*logn)...(这个地方的分析我先放放)