Question: enter an integer array with a positive or negative number in the array. One or more consecutive integers in the array form a sub-array. Each sub-array has a sum. Returns the maximum value of the sum of all sub-arrays. The time complexity is O (n ).
For example, the input array is 1,-2, 3, 10,-4, 7, 2,-5, and the maximum sub-array is 3, 10,-4, 7, 2, so the output is the sum of 18 of the Child array.
Without considering the time complexity, we can enumerate all sub-arrays and find their sum. However, it is a pity that the n-length array has an O (n2) Sub-array, and the time complexity of the sum of an array whose length is n is O (n ). Therefore, the time for this idea is O (n3 ).
It is easy to understand that when we add a positive number, it will increase; when we add a negative number, it will decrease. If the current sum is a negative number, the sum should be discarded and re-cleared in the following tired addition. Otherwise, the negative number will decrease the sum of the following values. Based on this idea, we can write the following code:
Copy codeThe Code is as follows :/*
// Find the greatest sum of all sub-arrays
// Return value: if the input is valid, return true, otherwise return false
Int * pData, // an array
Unsigned int nLength, // the length of array
Int & nGreatestSum // the greatest sum of all sub-arrays
*/
Int start, end;
Bool FindGreatestSumOfSubArray (int * pData, unsigned int nLength, int & nGreatestSum)
{
// If the input is invalid, return false
If (pData = NULL) | (nLength = 0 ))
Return false;
Int k = 0;
Int nCurSum = nGreatestSum = 0;
For (unsigned int I = 0; I <nLength; ++ I)
{
NCurSum + = pData [I];
// If the current sum is negative, discard it
If (nCurSum <0)
{
NCurSum = 0;
K = I + 1;
}
// If a greater sum is found, update the greatest sum
If (nCurSum> nGreatestSum)
{
NGreatestSum = nCurSum;
Start = k;
End = I;
}
}
// If all data are negative, find the greatest element in the array
If (nGreatestSum = 0)
{
NGreatestSum = pData [0];
For (unsigned int I = 1; I <nLength; ++ I)
{
If (pData [I]> nGreatestSum)
{
NGreatestSum = pData [I];
Start = end = I;
}
}
}
Return true;
}
Discussion: the above Code has two points worth discussing with you:
• The return value of a function is not the maximum value of a sub-array or a sub-array, but a flag for judging whether the input is valid. If the function returns the maximum values of sub-arrays, what should be returned when a null pointer is input? Returns 0? So how do users of this function distinguish between invalid input and the maximum value of the sub-array is exactly 0? Based on this consideration, I think that the sub-array and the maximum value are put in the parameter list as a reference, and the function returns a flag indicating whether the function is executed normally.
• Special processing is required for input in special cases. When All integers in the input array are negative, the maximum value of the sub-array and the sub-array is the maximum element in the array.
Method 2: programming beauty 2.14
Copy codeThe Code is as follows :/**
Calculate the largest sub-array and (the beauty of programming, returns the subscript and the beginning and end are not connected)
** Author: liuzhiwei
** Date: 2011-08-17
How to record the starting point and ending point Subscript:
Because I want subarrays whose start point and end point are both front-end subarrays, we 'd better move them forward in dynamic planning, in this way, the dp [I] indicates the value of the largest sub-array starting with I. When dp [I] and dp [j] are the same, we select I, small subscript in j as the starting point
**/
Int maxSum (int * arr, int n, int & start, int & end)
{
Int I, temp, dp, max;
Dp = max = arr [n-1];
Start = end = n-1;
Temp = n-1;
For (I = n-2; I> = 0; -- I)
{
If (dp> 0)
Dp + = arr [I];
Else
{
Dp = arr [I]; // discard the current subsequence
Temp = I; // start a new subsequence search
}
If (dp> max) // update the maximum subsequence
{
Max = dp;
End = temp;
Start = I; // maximum and increase. At this time, I must be the rightmost end.
}
}
Return max;
}
// Special test case-10-1-4
Another method for Traversing from the beginning to the end is as follows:Copy codeThe Code is as follows: // when you need to save the marker of the start point and end point, you can traverse from the beginning to the end.
Int MaxSum (int * a, int n)
{
Int tempstart = 0, sum = 0, max =-1000;
Int I, start, end;
Start = end = 0;
For (I = 0; I <n; ++ I)
{
If (sum <0)
{
Sum = a [I];
Tempstart = I;
}
Else
Sum + = a [I];
If (sum> max)
{
Max = sum;
Start = tempstart;
End = I;
}
}
Return max;
}
Expansion Question 1:
If the array is ring, that is, the first and end parts (the subscript of the element following the subscript N-1 is 0), calculate the maximum child segment and.
Resolution:
I think this problem is easier than the first one. There are many ways to solve it. I have introduced three methods, but one of them I think there is a problem, but as an exercise answer to the book "The beauty of programming", it may be that I have misunderstood the author's algorithm, I will discuss it later.
Method 1:
The optimal solution to this problem must be the following two possibilities. Possible 1: the optimal solution does not span a [n-1] to a [0], that is, the original problem, non-circular array. Possible 2: the optimal solution spans a [n-1] to a [0], a new problem.
In the first case, we can follow the simple dynamic planning solution and set it to max1. In the second case, we can convert the original problem to the minimum child segment and problem of the array, then use the sum of all elements in the array minus the minimum child segment sum, the result must be the largest child segment sum that spans a [n-1] to a [0] and is set to max2. The final result is the big one in max1 and max2.
Example 1: arrays 6,-1,-6, 8, and 2
If max1 = 10 and max2 = 16 are obtained, a large value of max2 is taken as the result.
Example 2: array-6, 8, 2, 6,-1
If max1 = 16 and max2 = 15 are obtained, a large value of max1 is taken as the result.
Some colleagues may have some questions about why: the array element "sum-Minimum sub-segment and = cross the maximum sub-segment and" in the case of a [n-1] to a [0. We can understand that the sum of n numbers is certain. If we find the continuous number of n numbers, and this number is the sum of all consecutive numbers and the smallest, therefore, the sum-minimum child segment and result must be the largest. Therefore, we can obtain the maximum sub-segment sum from a [n-1] to a [0.
The complete code is as follows:Copy codeThe Code is as follows: // calculates the sum of the largest sub-array and the ring array.
Int MaxSum (int * a, int n)
{
Int I, sum, max1, max2, dp, min;
Dp = max1 = a [0];
For (I = 1; I <n; ++ I) // The optimal solution does not span from a [n-1] to a [0], that is, the original problem, non-circular array
{
If (dp <0)
Dp = a [I];
Else
Dp + = a [I];
If (dp> max1)
Max1 = dp;
}
Sum = min = dp = a [0];
For (I = 1; I <n; ++ I) // you can convert the original question to the minimum child segment and question of the array, use the sum of all elements in the array minus the minimum child segment sum, then the result must be the largest child segment and
{
If (dp> 0)
Dp = a [I];
Else
Dp + = a [I];
If (dp <min)
Min = dp;
Sum + = a [I];
}
Max2 = sum-min; // sum of all elements of the array minus the minimum child segment and
Return max1> max2? Max1: max2; // returns a larger value.
}
The first part is to find the maximum value of max1 In the first case (Replace with the variable Max). In the second part, tmp is the minimum child segment and then tmp is sum-tmp; finally, Max takes a large number of the two.
Method 2:
Method 2 converts the problem into another problem: since the beginning and end of a piece of data can be connected, we can copy the array and connect it to our own backend, then we need to calculate the sum of the largest sub-array of the new array, but here we need to limit a condition that the length of the maximum sub-array cannot exceed n. In this way, we will turn the problem into expansion question 3. I will introduce it in the third part.
Method 3:
Method 3 is introduced in the book "The beauty of programming". For details, see the 188 page. However, I think this algorithm is incorrect. It may be because I have a problem understanding the author's ideas, I copied the solution below and gave a counterexample. If you are interested in the discussion, you may wish to leave a message for me.
From the beauty of programming P188:
If the Array (A [0], A [1], A [2],..., A [n-1]) is adjacent to the beginning and end, that is, we can find A number (A [I], A [I + 1],... A [n-1], A [0], A [1],..., A [j]) to maximize the sum. What should I do?
(1) The solution does not span A [n-1] to A [0] (original problem ).
(2) The solution spans A [n-1] to A [0].
In 2nd cases, you only need to find the first and largest segment from A [0] (A [0],…, A [j]) (0 <= j <n), and the largest and ending section (A [n-1],…, A [n-1]) (0 <= I <n), then, in the 2nd cases, the maximum M_2 of the sum is:
M_2 = A [I] +... + A [n-1] + A [0] +... + A [j]
If I <= j
M_2 = A [0] +... + A [n-1]
Otherwise
M_2 = A [0] +... + A [j] + A [I] +... + A [n-1]
Finally, we can take the maximum values of the two cases. To solve the problem that we have crossed A [n-1] to A [0], we only need to traverse the array once, so the total time complexity is O (N) + O (N) = O (N ).
Resolution:
There are no problems in the two cases, but I think the solution is wrong for the 2nd cases. The inverse example is as follows:
Evaluate the maximum sub-array of array 6,-1,-6, 8, 2 and: M_1 is 10. However, if the above method is used, the result obtained by M_2 is 9, because the first and largest segment of A [0] is A [0],…, A [n-1] is 9, ending with A [n-1] and the largest segment (A [I],…, A [n-1]) is A [n-1]. Because the two segments have intersection, M_2 = A [0] +... + A [n-1].
The final result is 9. If there are two cases, the result is 10. But the correct result is obviously 16.
The reason for this result: Although there is no error in finding the result starting from A [0] and the largest segment, the result we hope is not this segment, we hope to obtain the Section A [0] so that there will be no intersection between the two segments.
In the second part, I have analyzed two expansion problems, and I will analyze the other two expansion problems in the third part.
If I have written something wrong or you have a better method, I hope I can come up with it and learn from each other.
Expansion Question 2:
There is an integer series with negative numbers and positive numbers. The number of consecutive summation numbers and the absolute value of summation are the largest numerical strings.
Analysis
Ideas
Maximum child matrix and
Copy codeThe Code is as follows: # include <iostream>
# Include <cstdio>
Using namespace std;
# Include <memory. h>
Int a [102] [102];
Int maxSubArray (int * arr, int len) // maximum subsequence and
{
Int I, sum = arr [0], B = 0;
For (I = 0; I <len; ++ I)
{
If (B> 0)
B + = arr [I];
Else
B = arr [I];
If (B> sum)
Sum = B;
}
Return sum;
}
Int maxSubMatrix (int n, int m, int array [102] [102])
{
Int I, j, h, max, sum =-100000;
Int B [102];
For (I = 0; I <n; I ++)
{
Memset (B, 0, sizeof (B); // initialize B []
For (j = I; j <n; j ++) // adds row I to row j and returns the maximum value for each addition.
{
For (h = 0; h <m; h ++)
{
B [h] + = array [j] [h]; // compress a two-dimensional array into a one-dimensional array, and then obtain the maximum subsequence and
}
Max = maxSubArray (B, h );
If (max> sum)
Sum = max;
}
}
Return sum;
}
Int main (void)
{
Int n, I, j;
While (scanf ("% d", & n )! = EOF)
{
For (I = 0; I <n; I ++)
{
For (j = 0; j <n; j ++)
Scanf ("% d", & a [I] [j]);
}
Printf ("% d \ n", maxSubMatrix (n, n, ));
}
Return 0;
}