标签:
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 13 | -3 | -25 | 20 | -3 | -16 | -23 | 18 | 20 | -7 | 12 | -5 | -22 | 15 | -4 | 7 |
求这个数组中子数组的最大和。
我们来思考如何用分治法来求解最大子数组问题。假定我们要寻找子数组A[low,...,high]的最大子数组。使用分治技术,意味着我们要将子数组划分为两个规模尽量相等的子数组。也就是说,找到子数组的中央位置,比如mid,然后考虑求解两个子数组A[low,...,mid]和A[mid+1,..,high]。A[low,...,high]的任何连续子数组A[i,...,j]所处的位置必然是一下三种情况之一:
寻找跨越中点的最大子数组(O(N))伪代码:
find_max_crossing_subarray(a,low,mid,hight)left_sum = -65535sum = 0for i = mid dwonto lowsum = sum + A[i]if sum > left_sumleft_sum = summax_left = iright_sum = -65535sum = 0for j=mid+1 to highsum = sum +A[j]if sum>right_sumright_sum = summax_right = jreturn(max_left,max_right,left_sum+right_sum)
有了一个线性时间的find_max_crossing_subarray,我们就可以设计求解最大子数组问题的分治算法的伪代码了:
find_max_sumarray(A,low,high)if high==lowreturn(low,high,A[low]) //base case:only one elementelse mid = (low+high)/2(left_low,left_high,left_sum)= find_max_sumarray(A,low,mid)(cross_low,cross_high,right_sum) = find_max_sumarray(A,mid+1,high)if left_sum >= right_sum and left_sum >= cross_sumreturn (left_low,left_high,left_sum)elseif right_sum >= left_sum and right_sum >= cross_sumreturn (right_low,right_hight,right_sum)else return (cross_low,cross_high,cross_sum)
分治算法的时间分析:
使用如下思想为最大子数组问题设计一个非递归的,线性时间的算法。从数组的左边界开始,由左至右处理,记录到目前为止已经处理过的最大子数组。若已知A[1,...,j]的最大子数组,基于如下性质将解扩展为A[1,..,j+1]的最大子数组:
怎么找出来呢?
最优子结构:
设S[j]是以元素A[j]结尾的和最大子数组。那么已知j以前的状态,S[0],..,S[j-1]怎么求S[j]呢?
其实
/*求最大子数组的和,以及返回这个数组本身*/int MaxSubarray(const int * a, int size, int & from, int & to){if (!a || (size <= 0)){from = to = -1;return 0;}from = to = 0;int sum = a[0];int result = sum;int fromNew = 0; // 新的子数组起点for (int i = 0; i < size; i++){if (sum>0){sum += a[i];}else{sum = a[i];fromNew = i;}if (result < sum){result = sum;from = fromNew;to = i;}}return result;}
标签:
原文地址:http://www.cnblogs.com/gavin-yue/p/4975566.html