Vector [31,-41,59,26,-53,58,97,-93,-23,84]
Algorithm one: Direct solution, simple rough, no idea, complexity is O (N3)
//method One, close to O (N3) intmaxsofar1=0; intCount=0; for(inti =0; I <Ten; ++i) { for(intj =0; J <Ten; ++j) {intsum=0; for(intK = i; K < J; ++k) {sum+=Vec[k]; Count++; } maxsofar1=Max (maxsofar1,sum); }} cout<<maxsofar1<<" "<<count<<endl;
Algorithm two: The improvement of algorithm one, in fact, the second loop of the algorithm one and the third loop can be directly merged, so get the first O (N2) algorithm
intMaxsofar2=0; count=0; for(inti =0; I <Ten; ++i) {intsum=0; for(intj = i; J <Ten; ++j) {Sum+=Vec[j]; Count++; Maxsofar2=Max (maxsofar2,sum); }} cout<<maxsofar2<<" "<<count<<endl;
Change the method for sum to get another version
inttem[Ten]={0}; tem[0]=vec[0]; for(intI=1;i<Ten; i++) tem[i]=tem[i-1]+Vec[i]; Maxsofar2=0; Count=0; for(inti =0; I <Ten; ++i) {intsum=0; for(intj = i; J <Ten; ++j) {Sum=tem[j]-tem[i-1]; Count++; Maxsofar2=Max (maxsofar2,sum); }} cout<<maxsofar2<<" "<<count<<endl;
Algorithm three, divide and conquer algorithm, time complexity is O (NLog (n))
Principle of divide and conquer: To solve the problem of scale n, we can solve the sub-problem of two scale approaching N/2 recursively, and then merge their answers to get the answer of the whole question.
In this example, each time the vector is divided into the left and right two sub-vectors of approximate equal size A and B
Find the largest sub-vectors ma and MB in A and B, respectively
Then the answer is either in the MA, or in MB, or across the boundaries of A and B, in order for recursion to proceed smoothly, our Ma and MB are calculated from the middle of AB, respectively,
So if the maximum vector crosses the boundary of AB, then the maximum value is MA+MB, either MA or Mb
intMaxintAintBintc) {return((a>b) a:b) >c)? ((a>b)?a:b): C;}intA=0;intMAXSUM3 (intLintu) { if(L>u)return 0;//when the empty vector if(L==u)returnMax0, Vec[l]);//Vector has only one element intMid= (l+u)/2; intlmax,sum;lmax=sum=0; for(inti=mid;i>=l;--i) {sum+=Vec[i]; Lmax=Max (lmax,sum); A++; } intrmax;rmax=sum=0; for(intJ=mid+1; j<=u;++j) {Sum+=Vec[j]; A++; Rmax=Max (Sum,rmax); } returnMax (LMAX+RMAX,MAXSUM3 (L,mid), maxsum3 (mid+1, u));} cout<<MAXSUM3 (0,9) <<" "<<a<<endl;
algorithm four: scanning algorithm, O (n) time complexity is OK, is a linear algorithm
Algorithm thought: In the first I element, the maximal sub-vector is either in the first I-1 element, or its end position is I.
How do you understand that? You can understand this:
Vector [31,-41,59,26,-53,58,97,-93,-23,84]
We use a MAXSOFAR4 to store the maximum value and use Max_ending_here to store the largest value in the first I element.
Take our vector as an example, when I=1, maxsofar4=max_ending_here=31, but max_ending_here+vec[1]<0, so X_ending_here ended here, MAx_ Ending_here=0, and MAXSOFAR4 unchanged.
When i=2,Max_ending_here is used to record the maximum value of each time, when max_ending_here<0 is terminated, re-recorded, and MAXSOFAR4 recorded is max_ending_ Here the biggest one (result)
int maxsofar4=0, max_ending_here=0; for (int0; + +i) { max_ending_here=max (max_ending_here+vec[i],0); MAXSOFAR4=max (maxsofar4,max_ending_here); } cout<<maxsofar4<<endl;
Throughout the four algorithms, the simplest answer to the idea code is relatively long, the most complex idea code is the shortest, most efficient and the fastest, sometimes it is so magical, so sometimes do not rush to write code, ideas is the most important
Finally, we summarize several important algorithmic design techniques:
- Save state to avoid repeated calculations
- Preprocessing information into a data structure
- Divide and conquer algorithm
- Scanning algorithm: How to extend the solution of x[0...i-1] to X[0....I]
- Cumulative: Has a relationship with 2
- Nether: The best time complexity
Algorithm design--the maximal and problem of the continuous sub-vectors--on the importance of thought ideas