数据结构与算法分析 C 语言描述第二版第二章 最大子序列和问题

Maximum Subsequence Sum Problem

Maximum subsequence sum problem:
Given (possibly negative) integers A 1 , A 2 , , A N A_1, A_2, \cdots ,A_N , find the maximum value of k = i j A k \sum_{k = i}^j A_k . (For convenience, the maximum subsequence sum is 0 0 if all the integers are negative.)$

divide and conquer

The idea is to split the problem into two roughly equal subproblems, which are then solved recursively. This is the divide part.

The conquer stage consists of patching together the two solution of the subproblems, and possibly doing a small amount of additional work, to arrive at a solution for the whole problem.

In our case, the maximum subsequence sum can be in one of three places. Either it occurs entirely in the left half of the input, or entirely in the right half, or it crosses the middle and is in both halves.

The first two cases can be solved recursively.

The last case can be obtained by finding the largest sum in the first half that includes the last element in the first half, and the largest sum in the second half that includes the first element in the second half. The two sums can then be added together.

static int MaxSubSum(const int A[], int left, int right)
{
	int MaxLeftSum, MaxRightSum;
	int MaxLeftBorderSum, MaxRightBordedSum;
	int LeftBordedSum, RightBorderSum;
	int center, i;
	if (left == right) //base case
		if (A[left] > 0)
			return A[left];
		else
			return 0;
	center = (left + right) / 2;
	MaxLeftSum = MaxSubSum(A, left, center);
	MaxRightSum = MaxSubSum(A, center+1, Right);
	MaxLeftBorderSum = 0; LeftBorderSum = 0;
	for (i = center; i >= left; i--) {
		LeftBorderSum += A[i];
		if (LeftBorserSum > MaxLeftBorderSum)
			MaxLeftBorderSum = LeftBorderSum;
	}
	MaxRightBorderSum = 0; RightBorderSum = 0;
	for (i = center+1; i <= right; i++) {
		RightBorderSum += A[i];
		if (RightBorderSum > MaxRightBorderSum)
			MaxRightBorderSum = RightBorderSum;
	}
	return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
} 
int MaxSubsequenceSum(const int A[], int N)
{
	return MaxSubSum(A, 0, N-1);
}

Running time

Let T ( N ) T(N) be the time it takes to solve a maximum subsequence sum problem of size N N .

If N = 1 N = 1 , then the program takes constant amount of time to execute lines 7 to 10, which we shall call one unit. Thus T ( 1 ) = 1 T(1) = 1 .

Otherwise, the program must perform two recursive calls,the two for loops between lines 15 and 23, and some small aomont of bookkeeping, such as lines 11 and 24.

The two for loops combine to touch every element form A 0 A_0 to A N 1 A_{N-1} , and there is constant work inside the loops, so the time expended in lines 15 to 23 is O ( N ) O(N) .

The code in lines 7 to 11, 14, 19, and 23 is all a constant amount of work and can thus be ignored compared with O ( N ) O(N) .

The remainder of work is performed in line 12 and 13. These lines solve two subsequence problems of size N / 2 N/2 (assuming N is even). Thus , these lines take T ( N / 2 ) T(N/2) units of time each, for a total of 2 T ( N / 2 ) 2T(N/2) .

The total time is 2 T ( N / 2 ) + O ( N ) 2T(N/2) + O(N) .

This gives the equations:
T ( 1 ) = 1 T(1) = 1
T ( N ) = 2 T ( N / 2 ) + O ( N ) T(N) = 2T(N/2) + O(N)

To simplify the calculations, we can replace the O ( N ) O(N) term in the equation above with N N ; since T ( N ) T(N) will be expressed in B i g O h Big-Oh notation anyway, this whill not affect the answer.

If T ( N ) = 2 T ( N / 2 ) + N T(N) = 2T(N/2) + N , and T ( 1 ) = 1 T(1) = 1 , then T ( 2 ) = 4 = 2 2 T(2) = 4 = 2 * 2 , T ( 4 ) = 12 = 4 3 T(4) = 12 = 4 * 3 , T ( 8 ) = 32 = 8 4 T(8) = 32 = 8 * 4 , T ( 16 ) = 80 = 16 5 T(16) = 80 = 16 * 5 .

If N = 2 k N = 2^k , then T ( N ) = N ( k + 1 ) = N l o g N + N = O ( N l o g N ) T(N) = N * (k+1) = NlogN + N = O(NlogN) .

Kadane’s Algorithm

参见:Kadane’s Algorithm — (Dynamic Programming) — For new Solvers!

int MaxSubsequenceSum(const int A[], int N)
{
	int ThisSum = 0, MaxSum = 0, j;
	for (j = 0; j < N; j++) {
		ThisSum += A[j];
		if (ThisSum > MaxSum)
			MaxSum = ThisSum;
		else if (ThisSum < 0)
			ThisSum = 0;
	} 
	return MaxSum;
}

This algorithm is simpler to implement than the recursive algorithm and also is more efficient. It runs in O ( N ) O(N) time.

发布了120 篇原创文章 · 获赞 2 · 访问量 5800

猜你喜欢

转载自blog.csdn.net/Lee567/article/details/103282798