一、问题描述
给定由n个整数组成的序列(a_1,a_2,…,a_n),最大子段和问题要求该序列形如
的最大值(1≤i≤j≤n),当序列中所有整数均为负整数时,其最大子段和为0。
例如,序列(-20, 11, -4, 13, -5, -2)的最大子段和为:
注意:必须是连续整数的和。
二、分治策略
(1)划分
–按照平衡子问题的原则,将序列(
,
,…,
) 划分成长度相同的两个子序列(
,…,
)和(
,…,
),则会出现以下三种情况:
①
,
,…,
的最大子段和 =
,…,
的最大子段和;
②
,
,…,
的最大子段和 =
,…,
的最大子段和;
③
,
,…,
的最大子段和 =
, 且1≤i≤⌊
⌋ , ⌊
⌋+1≤j≤n
(2)求解子问题
对于划分阶段的情况①和②可递归求解
对情况③,分别计算
则
为情况③的最大子段和。
(3)合并
–比较在划分阶段的三种情况下的最大子段和,取三者之中的较大者为原问题的解。
三、算法实现
int MaxSum(int a[ ], int left, int right){sum=0;if (left= =right) { //如果序列长度为1,直接求解if (a[left]>0) sum=a[left];else sum=0;}else {center=(left+right)/2; //划分leftsum=MaxSum(a, left, center); //对应情况①,递归求解rightsum=MaxSum(a, center+1, right); //对应情况②,递归求解s1=0; lefts=0; //以下对应情况③,先求解s1for (i=center; i>=left; i--) {lefts+=a[i];if (lefts>s1) s1=lefts;}s2=0; rights=0; //再求解s2for (j=center+1; j<=right; j++) { rights+=a[j];if (rights>s2) s2=rights;}sum=s1+s2; //计算情况③的最大子段和 if (sum<leftsum) sum=leftsum; //合并,在sum、leftsum和rightsum中取较大者if (sum<rightsum) sum=rightsum;}return sum;
}
思考:采用分治法求解(-20,11,-4,13,-5,-2)的最大子段和, 写出求解过程。
四、时间复杂度分析
对应划分得到的情况①和②,需要分别递归求解;
对应情况③,两个并列for循环的时间复杂性是O(n),所以,存在如下递推式:
综上,时间复杂性为O(nlog2n)。
内容有待完善,请客官等待更新!