Problem description:
Enter a group of Integers to obtain the subsequence of the numbers and the medium and maximum values. That is, as long as the sum of the largest subsequences is obtained, the largest sequence does not need to be obtained. For example:
Sequence:-2 11-4 13-5-2, then the maximum subsequence is 20.
Sequence:-6 2 4-7 5 3 2-1 6-9 10-2, the maximum subsequence is 16.
Algorithm 1:
// The exhaustive method. complexity O (n ^ 3) is the easiest and simplest algorithm to think.
[Cpp]
<SPAN style = "FONT-SIZE: 14px"> long maxSubSum1 (const vector <int> &)
{
Long maxSum = 0;
For (int I = 0; I <a. size (); I ++)
{
For (int j = I; j <a. size (); j ++)
{
Long thisSum = 0;
For (int k = I; k <= j; k ++)
{
ThisSum + = a [k];
}
If (thisSum> maxSum)
MaxSum = thisSum;
}
}
Return maxSum;
} </SPAN>
Long maxSubSum1 (const vector <int> &)
{
Long maxSum = 0;
For (int I = 0; I <a. size (); I ++)
{
For (int j = I; j <a. size (); j ++)
{
Long thisSum = 0;
For (int k = I; k <= j; k ++)
{
ThisSum + = a [k];
}
If (thisSum> maxSum)
MaxSum = thisSum;
}
}
Return maxSum;
}
This is an O (N ^ 3) algorithm, which is easy to understand and intuitively feels useless. For example, when I = 0, j = 3, a [0] + a [1] +... + A [3]; when I = 0, j = 4, a [0] + a [1] +... A [4].
Algorithm 2:
Avoid three times by removing a for loop.
// It is also an exhaustive method, but some unnecessary operations O (n ^ 2) are subtracted from the above)
[Cpp]
<SPAN style = "FONT-SIZE: 14px"> long maxSubSum2 (const vector <int> &)
{
Long maxSum = 0;
For (int I = 0; I <a. size (); I ++)
{
Long thisSum = 0;
For (int j = I; j <a. size (); j ++)
{
ThisSum + = a [j];
If (thisSum> maxSum)
MaxSum = thisSum;
}
}
Return maxSum;
} </SPAN>
Long maxSubSum2 (const vector <int> &)
{
Long maxSum = 0;
For (int I = 0; I <a. size (); I ++)
{
Long thisSum = 0;
For (int j = I; j <a. size (); j ++)
{
ThisSum + = a [j];
If (thisSum> maxSum)
MaxSum = thisSum;
}
}
Return maxSum;
}
This is a very intuitive method (simpler than the above analysis), and there are no redundant operations, the complexity is O (N ^ 2 ). Here, thisSum indicates a [I] + a [I + 1] +... + A [J-1].
Algorithm 3:
There is a relatively complex O (NlogN) solution for this problem, that is, recursion. If we find the position of the sequence, this will be the best algorithm (because we will have an O (N) algorithm later, but we cannot find the position of the largest subsequence ). In this method, we use divide-and-conquer ).
In our example, the largest subsequence may appear in three places, or in the left half, or in the right half, or across the middle of the input data, occupying the Left and Right Parts. In the first two cases, recursive solutions are provided. In the third case, the largest sum is obtained, and the largest sum of the first half is obtained (including the last element of the first half) and the largest sum of the second half (the first element that contains the second half.
// Recursive method, complexity is O (nlogn)
[Cpp]
<SPAN style = "FONT-SIZE: 14px"> long maxSumRec (const vector <int> & a, int left, int right)
{
If (left = right)
{
If (a [left]> 0)
Return a [left];
Else
Return 0;
}
Int center = (left + right)/2;
Long maxLeftSum = maxSumRec (a, left, center );
Long maxRightSum = maxSumRec (a, center + 1, right );
// Obtain the maximum value of the sequence ending with the last digit on the left.
Long maxLeftBorderSum = 0, leftBorderSum = 0;
For (int I = center; I> = left; I --)
{
LeftBorderSum + = a [I];
If (leftBorderSum> maxLeftBorderSum)
MaxLeftBorderSum = leftBorderSum;
}
// Obtain the maximum value of the sequence ending with the last digit on the right.
Long maxRightBorderSum = 0, rightBorderSum = 0;
For (int j = center + 1; j <= right; j ++)
{
RightBorderSum + = a [j];
If (rightBorderSum> maxRightBorderSum)
MaxRightBorderSum = rightBorderSum;
}
Return max3 (maxLeftSum, maxRightSum,
MaxLeftBorderSum + maxRightBorderSum );
}
Long maxSubSum3 (const vector <int> &)
{
Return maxSumRec (a, 0, a. size ()-1 );
}
In addition, max3 (long, long, long) indicates to calculate the maximum value of the three long:
// Obtain the maximum value among the three long strings.
Long max3 (long a, long B, long c)
{
If (a <B)
{
A = B;
}
If (a> c)
Return;
Else
Return c;
} </SPAN>
Long maxSumRec (const vector <int> & a, int left, int right)
{
If (left = right)
{
If (a [left]> 0)
Return a [left];
Else
Return 0;
}
Int center = (left + right)/2;
Long maxLeftSum = maxSumRec (a, left, center );
Long maxRightSum = maxSumRec (a, center + 1, right );
// Obtain the maximum value of the sequence ending with the last digit on the left.
Long maxLeftBorderSum = 0, leftBorderSum = 0;
For (int I = center; I> = left; I --)
{
LeftBorderSum + = a [I];
If (leftBorderSum> maxLeftBorderSum)
MaxLeftBorderSum = leftBorderSum;
}
// Obtain the maximum value of the sequence ending with the last digit on the right.
Long maxRightBorderSum = 0, rightBorderSum = 0;
For (int j = center + 1; j <= right; j ++)
{
RightBorderSum + = a [j];
If (rightBorderSum> maxRightBorderSum)
MaxRightBorderSum = rightBorderSum;
}
Return max3 (maxLeftSum, maxRightSum,
MaxLeftBorderSum + maxRightBorderSum );
}
Long maxSubSum3 (const vector <int> &)
{
Return maxSumRec (a, 0, a. size ()-1 );
}
In addition, max3 (long, long, long) indicates to calculate the maximum value of the three long:
// Obtain the maximum value among the three long strings.
Long max3 (long a, long B, long c)
{
If (a <B)
{
A = B;
}
If (a> c)
Return;
Else
Return c;
}
Analyze this algorithm:
T (1) = 1
T (N) = 2 T (N/2) + O (N)
Finally, the complexity of the algorithm is O (NlogN ).
Algorithm 4:
Next we will introduce a linear algorithm, which is typical of many smart algorithms: the running time is obvious, but the correctness is not obvious (not easy to understand ).
// Linear algorithm O (N)
[Cpp]
<SPAN style = "FONT-SIZE: 14px"> long maxSubSum4 (const vector <int> &)
{
Long maxSum = 0, thisSum = 0;
For (int j = 0; j <a. size (); j ++)
{
ThisSum + = a [j];
If (thisSum> maxSum)
MaxSum = thisSum;
Else if (thisSum <0)
ThisSum = 0;
}
Return maxSum;
} </SPAN>
Long maxSubSum4 (const vector <int> &)
{
Long maxSum = 0, thisSum = 0;
For (int j = 0; j <a. size (); j ++)
{
ThisSum + = a [j];
If (thisSum> maxSum)
MaxSum = thisSum;
Else if (thisSum <0)
ThisSum = 0;
}
Return maxSum;
}
It is easy to understand that O (N) in the time field is correct, but it is effort-consuming to figure out why it is correct. In fact, this is an improvement of algorithm 2. During analysis, I represents the starting point of the current sequence, and j represents the end point of the current sequence. If we don't need to know the location of the best sub-sequence, I can be optimized.
One important idea is that if a [I] is a negative number, it cannot represent the starting point of the most sequential order, any subsequence containing a [I] as the starting point can be improved by using a [I + 1] as the starting point. Similarly, any negative subsequence cannot be the prefix of the optimal subsequence. For example, if we find that the subsequence from a [I] to a [j] is a negative number in a loop, we can promote I. The key conclusion is that we can not only push I to I + 1, but also push it to j + 1.
For example, p is any subscript between I + 1 and j... + A [j] is a negative number, then, any subsequence starting with subscript p will not be greater than the subsequence corresponding to subscript I and include the subsequence from a [I] to P-1. ). Therefore, it is safe to push I to j + 1 without missing the optimal solution. Note: although, if there is a sequence ending with a [j] and a negative number, it indicates that any number in the sequence cannot start with the largest subsequence formed by the number following a [j ]., however, it does not indicate that a sequence before a [j] is not the largest sequence. That is to say, it cannot be determined whether the maximum subsequence is before a [j] or after a [j, that is, the maximum subsequence position cannot be obtained. However, we can ensure that the maxSum value is the largest subsequence sum currently. This algorithm only scans data once. Once a [j] is read and processed, it does not need to be memorized. It is an online algorithm. Online algorithms: at any time, the algorithm can provide the current data solution for the data it has read.