分治法求最大子序列
假设序列为a[9] = {4,-3,5,-2,-1,2,6,-2,3}算法思想
采用二分策略
我们知道,最大子序列出现的可能只有三种:
1. 只出现在前半部分;
2. 只出现在后半部分;
3. 横跨了整个序列。
我们只需把三种可能的最大子序列和都求出,然后找到其中最大的那个,就是这个序列的最大子序列了。然后用递归的方法就可求出整个序列的最大子序列以及最大子序列之和了。
在这个序列中前半部分的最大子序列是[a0, a1, a2],和为6;后半部分的最大子序列是[a5, a6],和为8;而第三种情况下的最大子序列为[a0, a1, a2, a3, a4, a5, a6, a7, a8],和为12
此类算法的难点:
在第三种情况下最大子序列的求解。分析第三种情况下的特点,我们发现所求的最大子序列肯定是从中间的开始往左右延伸的。
所以在求解时可以对前半部分从右往左求和,找出求和过程中出现的最大求和值lMaxSum;对后半部分也是类似,从左往右求和,找出出现的最大求和值rMaxSum,然后两者相加就得到第三种情况下的最大自序列。
代码
#include <stdio.h> int Max2(int a, int b) { return a>b ? a:b; } int Max3(int a, int b, int c) { int max = a; if(max < b) max = b; if(max < c) max = c; return max; } int MaxSubSum(int* a, int fI, int lI) { int i = 0; int mI = (fI+lI) >> 1; int lMax = 0, rMax = 0, lMaxBorder = 0, rMaxBorder = 0, lSumBorder = 0, rSumBorder = 0, max = 0; //so how about if(fI == lI) return *(a+fI); lMax = MaxSubSum(a, fI, mI); rMax = MaxSubSum(a, mI+1, lI); for(i=mI;i>=fI;i--) { lSumBorder += *(a+i); if(lMaxBorder < lSumBorder) lMaxBorder = lSumBorder; } for(i=mI+1;i<=lI;i++) { rSumBorder += *(a+i); if(rMaxBorder < rSumBorder) rMaxBorder = rSumBorder; } max = Max3(lMax, rMax, lMaxBorder+rMaxBorder); return max; } int main() { int a[9] = {4,-3,5,-2,-1,2,6,-2,3}; int L = sizeof(a) / sizeof(int); int max = MaxSubSum(a, 0, L-1); printf("%d \n", max); return 0; }
补充:软件开发 , C++ ,