数据结构与算法分析 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 A1,A2,,AN, find the maximum value of ∑ k = i j A k \sum_{k = i}^j A_k k=ijAk. (For convenience, the maximum subsequence sum is 0 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;
	//divide 求出 左边和右边的最大子序列和	
	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) T(N) be the time it takes to solve a maximum subsequence sum problem of size N N N.

If N = 1 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 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 A0 to A N − 1 A_{N-1} AN1, and there is constant work inside the loops, so the time expended in lines 15 to 23 is O ( N ) 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) 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 N/2(assuming N N N is even). Thus , these lines take T ( N / 2 ) T(N/2) T(N/2) units of time each, for a total of 2 T ( N / 2 ) 2T(N/2) 2T(N/2).

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

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

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

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

If N = 2 k N = 2^k N=2k, 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) 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) O(N) time.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值