Maximum sub-array problem
This article is just a record, more detailed ideas please view the introduction of algorithms
Maximum sub-array structure body
typedef struct { int low, high, sum;} SubArray;
Brute Force Solution
Computes all the array intervals and then gets the largest sub-array, the algorithm complexity is θ (n2). This approach is good for small-scale data, but it is bad in large-scale data, but it can be used as an improvement in the divide-and-conquer algorithm. The idea is to first calculate the i
maximum number of sub-arrays from the beginning, and then from [1..N],[2..N]. [N.. N] to find the largest sub-array.
subarray maxsubarray_bruteforce (int low, int. high, int a[]) {int sum; int max_subarray = 0; Subarray *s = (Subarray *) calloc ((high-low + 2), sizeof (Subarray)); for (int i = low, k = 0; I <= high; ++i, ++k) {s[k].sum = Int_min; S[k].low = i; sum = 0; for (int j = i, J <= High; ++j) {//calculates the maximum subarray from the start with ' i ' sum + = a[j]; if (S[k].sum < sum) {s[k].sum = sum; S[k].high = j; }} if (S[max_subarray].sum <= s[k].sum)//= is the case where {0,0,1} is present the exact computed sub-array is [2,2]{1} max_sub Array = I-low; } return S[max_subarray];}
Divide and conquer algorithm
From the time analysis of the divide-and-conquer algorithm,
$$
T (n) =\begin{cases}
\theta (1) & if & n = 1 \
A\theta (n/a) + \theta (n.) & if & n > 1
\end{cases}
$$
If you are looking for [low. High], using the technique of divide and conquer means that we want to divide the array into two sub-arrays of the same size as possible (top A is 2), find the middle position mid, and then consider solving the sub-array [Low. Mid] and [Mid+1..high]. Array [Low.. Maximum sub-array of high] [I.. J] must be the following three cases:
- Exactly in the sub-array [Low.. Mid], so
low <= i <= high <= mid
- is completely in the sub-array [Mid+1..high], so
mid+1 <= i <= j <= high
- Midpoint mid is cross-domain, so it's located
low <= i <= mid <= j <= high
and specify that the array across the midpoint must contain mid and Mid + 1
To solve a sub-array recursively [low.. Mid] and [Mid+1..high], reducing the size of the problem, and finally looking for the largest sub-array across the midpoint, similar to the merging process of the merge sort, we take the largest sub-array that crosses the midpoint as the merging process of sub-problems. The simple logic is
- Looking for sub-arrays [Low: The largest sub-array of mid]
- Finding the largest subarray of sub-arrays [Mid+1..high]
- Looking for [low.. The largest sub-array of mid Mid+1..high]
- Returns a subarray of three maximum sub-arrays. Note: The comparison here must be preceded by an equal sign, so that you can skip over 0 to find the maximum subarray more precisely.
subarray maxcrosssubarray (int low, int mid, int. High, int a[]) {int left_sum, right_sum, sum; Subarray S; Left_sum = Right_sum = Int_min; sum = 0; for (int i = Mid, I >= low; i--) {sum + = A[i]; if (Left_sum < sum) {s.low = i; Left_sum = sum; }} sum = 0; for (int j = mid + 1, J <= High; j + +) {sum + = a[j]; if (Right_sum < sum) {S.high = J; Right_sum = sum; }} s.sum = Left_sum + right_sum; return S;} Subarray maxsubarray_divideconquer (int low, int. High, Int. a[]) {if (low = = high) {Subarray S; S.low = low; S.high = high; S.sum = A[low]; return S; } int mid = (low + high)/2; Subarray L = Maxsubarray_divideconquer (Low, Mid, A); Subarray R = Maxsubarray_divideconquer (mid + 1, high, A); Subarray M = Maxcrosssubarray (Low, Mid, High, A); Return Max3 (L, R, M);}
Improved recursive algorithm
The above mentioned brute force solution is very poor in large-scale data, but it has great advantages in small-scale solution. When the size of a sub-problem is less than a certain value n
, we use brute force algorithms to solve
// 暴力算法和分治算法在 40 左右达到性能交叉点// 在规模在 10 左右,暴力算法大幅领先分治算法SubArray MaxSubArray_Synergy(int low, int high, int A[]) { if (high - low < 10) return MaxSubArray_BruteForce(low, high, A); int mid = (low + high) / 2; SubArray L = MaxSubArray_Synergy(low, mid, A); SubArray R = MaxSubArray_Synergy(mid + 1, high, A); SubArray M = MaxCrossSubArray(low, mid, high, A); return Max3(L, R, M);}
Linear algorithm
The largest subarray of known [1..J], calculates the idea of [1..j+1] maximal subarray: The largest subarray of [1..j+1] is either the largest sub-array of [1..J] or a subarray [i. J+1] (1 <= i <= j+1). Specific implementations as described in the notes
SubArray MaxSubArray_Linear(int low, int high, int A[]) { SubArray S = {-1, -1, INT_MIN}; int sum = 0; int slow = -1; for (int i = low; i <= high; ++i) { if (sum > 0) { // 加上A[i]后当前最大子数组为正,中间的非负数项继续保留 sum += A[i]; } else { // 重新寻找最大子数组 sum = A[i]; slow = i; } if (sum > S.sum) { // 新的最大子数组大于旧最大子数组 S.low = slow; S.high = i; S.sum = sum; } }
Some of the problems that are encountered while writing code
- At first, my recursive implementation is also a subarray pointer, but in memory the real subarray only one copy, every time the calculation subarray variable is changing. In fact, we only need the subscript and the sub-array, so directly within the function definition wait until the function end stack memory recycling is not related, because it has been returned.
- The first I of the brute-force algorithm starts with 0, and if it's just a simple call, it's not going to be a problem, but when the recursive algorithm takes a small call, a segment error occurs (out of bounds)
- The maximum subarray size is the same, but the subscript of several algorithms is not the same, the problem is that there is no 0 filtering, as in the linear algorithm should be if (Sum > 0) and should not be if (sum >= 0), the Max3 of the recursive algorithm to compare the largest sub-array of the problem should be coupled with an equal judgment. There is also this situation {1, 1,-2, 1, 1}, these algorithms appear two answers [0-1] and [3-4], this problem is not resolved
The time complexity of the four algorithms:
$$
\begin{cases}
Bruteforce & \theta (n^2) & \
Divideconquer & \theta (Nlog (n)) \
Bruteforce+divideconquer & \theta (Nlog (n)) \
Linear & \theta (n)
\end{cases}
$$
Processing 10w (why not a larger number, because the brute force algorithm is too slow), the time of four algorithms is probably
- Brute Force algorithm 15.12s
- Simple recursive algorithm 0.15s
- Optimized recursive algorithm 0.12s
- Linear algorithm ignores 0.003s
Maximum sub-array problem