Finding the largest sub-array in an array is a classic question ,《AlgorithmIn the introduction, there is a classic solution for divide and conquer, and time complexity can be O (nlgn ).
This issue is discussed in the beauty of programming and the pearl of programming. One of the dynamic planning practices is very delicate, the idea is very good, and the time complexity is optimized to O (n ).
The two solutions mentioned above are very enlightening in terms of the division and Control Law and dynamic planning. They are very good exercises.
(1) divide and conquer law:
The key idea is to translate a large question into solving multiple sub-questions.
If we divide the array arr [] into two halves of the same size: arr_a and arr_ B, there are only three possibilities for the maximum and sub of the current array:
1) sub is completely in arr_a.
2) sub is completely in arr_ B.
3) sub spans arr_a and arr_ B.
For 1), 2) This is obviously a subproblem of the current problem and can be solved recursively.
3 ).
For 3), it can be converted to the following problem:
Assume that the center point is mid, and a child array containing the largest and ARR [Mid] is obtained.
This problem is equivalent to finding a child array whose arr [Mid] is the last element and the largest, and calculate a child array starting with arr [Mid] and the largest.
These two problems can be solved through accumulation.
Struct Tuple { Int S; Int E; Int SUM;}; tuple maxsub ( Int Arr [], Int Low, Int High ){ If (Low < High ){ Int Mid = (low + high )/ 2 ; Tuple left = Maxsub (ARR, low, mid); tuple right = Maxsub (ARR, Mid + 1 , High); tuple middle = Maxmiddle (ARR, low, high ); Return Max (left, right, middle);} return {low, low, arr [low]};}
As for maxmiddle, we can directly perform brute-force computing.
Tuple maxmiddle ( Int Arr,Int Low, Int High ){ Int Mid = (low + high )/ 2 ; Int Max_left = 0 , Li = mid, tmp_sum = 0 ; For ( Int I = mid; I> = 0 ; I -- ) {Tmp_sum + =Arr [I]; If (Tmp_sum> Max_left) {max_left = Tmp_sum; Li = I ;}} Int Max_right = 0 , RI = Mid; tmp_sum = 0 ; For ( Int I = mid; I I) {tmp_sum + = Arr [I]; If (Tmp_sum> Max_right) {max_right = Tmp_sum; ri = I ;}} Return {Li, RI, max_left + max_right- Arr [Mid]};}
The benefit of using the divide and conquer method here is that the idea is very clear,CodeIt is also easy to write, and the time complexity is well controlled.
But there are better solutions for this question, such as dynamic planning.
(2) Dynamic Planning:
The idea of this solution is similar to that of some gods.
Consider the following:
For array arr [0]... arr [N].
Suppose we have obtained the sub-array: arr [1]... the largest sub-array arr [I] of ARR [N]... arr [J]. and the largest sub-array starting with arr [1]: arr [1]... arr [e].
Therefore, the largest sub-array of ARR [0]... arr [N] must be one of the following three conditions:
1) Arr [0],
2) Arr [0] + arr [1] +... + arr [e].
3) Arr [I] +... + arr [J].
Therefore, the question is how to obtain the maximum sub-array sum of the sub-array arr [1]... arr [N], and the sub-array and the maximum sub-array switched by arr [1.
For arr [N], it is clear that its maximum sub-array is arr [N], and its maximum sub-array starting with arr [N] is also arr [N].
Assume that the maximum sub-array of ARR [k]... arr [N] is: arr [Ki]... arr [kJ].
The maximum sub-array starting with arr [k] is: arr [k]... arr [ke].
There are only two conditions for the largest child array that begins with arr [k-1] For arr [k-1]... arr [N:
1) Arr [k-1].
2) Arr [k-1] + arr [k] +... + arr [ke].
The maximum sub-array of ARR [-1]... arr [N] has two conditions:
1) The largest sub-array starting with arr [k-1] is the result obtained above.
2) The maximum sub-array of ARR [k]... arr [N.
Void Sovle ( Int Arr [], Int Sz ){ Int Max [SZ]; Int Max2 [SZ]; Max [SZ - 1 ] = Arr [SZ- 1 ]; Max2 [SZ - 1 ] = Arr [SZ- 1 ]; For ( Int I = SZ- 2 ; I> = 0 ;-- I ){ If (Max2 [I + 1 )> = 0 ) Max2 [I] = Arr [I] + max2 [I + 1 ]; Else Max2 [I] = Arr [I]; If (Max2 [I]> MAX [I + 1 ]) Max [I] = MAX [ 2 ]; Else Max [I] = MAX [I + 1 ];} Cout <MAX [ 0 ] < Endl ;}
Dynamic Planning is clever, and the time complexity is optimized to O (n ).
In the pseudo code above, the space complexity is O (n). In fact, it can be optimized to O (1). I will not introduce it here.
(3)
I met this question for the first time when I was at school. I didn't think deeply or complex as I mentioned in the above books, but I also found a relatively shanzhai solution, time complexity can be O (n ).
In fact, the question is not very difficult. We only need to have a variable to record the sum currently accumulated, and the largest sum found so far, to scan the array, you can get the answer.
1) Assume that arr [0] is the first element of the Child array to be searched, sum = arr [0], temp_sum = arr [0];
S = E = Ts = TE = 0; (Note: S = start, E = end, TS = temp start, TE = temp end)
2) temp_sum + = arr [I]; I = 1, 2, 3 ,....
3)
A) if temp_sum> sum, S = ts, E = tE.
B) If temp_sum <0, TS = TE = I + 1; temp_sum = 0;
It is correct to move ts to I here, because here temp_sum <0 indicates that the previous arrays are all negative and there is no need to accumulate them again.
# Include <iostream> Using Namespace STD; Void Solve ( Int Arr [], Int Sz ){ Int Max, mi, MJ; Int I, m; max = Arr [ 0 ]; Mi = Mj = 0 ; M = I = 0 ; For ( Int S = 0 ; S <SZ; ++ S) {m + = Arr [s]; If (M>Max) {max = M; Mi = I; MJ = S ;} If (M < 0 ) {I = S + 1 ; M = 0 ;}} If (MI < Sz) cout <" Max sub-array: From " <Mi < " To " <MJ < " , Sum = " <Max < Endl ;} Int Main (){ Int * Arrs [] = {{ 1 ,2 , 3 , 4 , 5 },{ - 2 , 2 , 3 ,- 4 , 3 },{ - 100 , 100 ,- 1 , 100 ,- 100 }}; Return ;}