标签:
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 = -65535
sum = 0
for i = mid dwonto low
sum = sum + A[i]
if sum > left_sum
left_sum = sum
max_left = i
right_sum = -65535
sum = 0
for j=mid+1 to high
sum = sum +A[j]
if sum>right_sum
right_sum = sum
max_right = j
return(max_left,max_right,left_sum+right_sum)
有了一个线性时间的find_max_crossing_subarray,我们就可以设计求解最大子数组问题的分治算法的伪代码了:
find_max_sumarray(A,low,high)
if high==low
return(low,high,A[low]) //base case:only one element
else 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_sum
return (left_low,left_high,left_sum)
elseif right_sum >= left_sum and right_sum >= cross_sum
return (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