分治——最大连续数组和
问题描述:
给一个整数数组,求其所有子数组中和最大的子数组在所给整数数组的的起始位置与终点;
方法一:穷举每个子数组,时间复杂度为o(N2);
方法三:时间复杂度为O(N); 请自行查阅书籍;
方法二:
采用分治思想:
先将数组从中间(分割点)分成两部分(和最大子数组要么在其左边,要么在其右边,或者跨过分割点),先求出左边和最大的子数组,再求右边和最大的子数组,
然后求经过中间分隔点的最大子数组和;
如何求经过中间分隔点的最大子数组和:从分割点开始向左累加求和,找到其和最大的的位置与所求和的值,再从分割点开始向右累加求和,找到其和最大的的位置与所求和的值。
1 #include<iostream> 2 using namespace std; 3 struct sub{ //定义一个子数组起点,终点与其所有元素和 4 int start; 5 int end; 6 7 int sum; 8 }; 9 10 sub merge(sub sub1,int start,int end,int A[]) // 11 { 12 int leftSum=0,rightSum=0,leftPos=(start+end)/2,rightPos=(start+end)/2+1,leftMax=-10000,rightMax=-10000; 13 14 for(int i=(start+end)/2;i>=start;i--) 15 { 16 leftSum+=A[i]; //求最大数组和的起点 17 if(leftMax<leftSum) 18 { 19 leftPos=i; 20 leftMax=leftSum; 21 } 22 } 23 24 for(int i=(start+end)/2;i<=end;i++) 25 { 26 rightSum+=A[i]; 27 if(rightMax<rightSum) //求最大数组和的终点 28 { 29 rightPos=i; 30 rightMax=rightSum; 31 } 32 } 33 34 if ( sub1.sum< (rightMax+leftMax) ) 35 { 36 sub1.start=leftPos; 37 sub1.end=rightPos; 38 sub1.sum= (rightMax+leftMax); 39 } 40 41 return sub1; 42 } 43 sub recursion(int start,int end,int A[]) 44 { 45 sub sub1,sub2; 46 47 if(start<end) 48 { 49 sub1=recursion(start,(start+end)/2,A); 50 sub2=recursion((start+end)/2+1,end,A); 51 52 sub1=sub1.sum>sub2.sum?sub1:sub2; 53 54 return merge(sub1,start,end,A); 55 } 56 57 sub1.start=sub1.end=start; 58 sub1.sum=A[start]; 59 60 return sub1; 61 } 62 int main() 63 { 64 int a[]={1,-5,9,8,-3,-6,11}; 65 66 sub sub1=recursion(0,6,a); 67 68 cout<<sub1.start<<" to "<<sub1.end<<" sum:"<<sub1.sum<<endl; 69 70 } 71