最大子序列和问题 分治算法

问题:给定整数A1,A2,·······,An,求该序列中所有子序列(包括本序列)中的元素和最大值,如果所有整数均为负数,则最大子序列和为0

算法一:穷举法。运行时间为O(N3)

代码:

int MaxSubsequenceSum(const int A[], int N)
{
	int ThisSum, MaxSum, i,j,k;

	MaxSum = 0;
	for(i = 0; i< N; i++)
	{
		for(j = i; j < N; j++)
		{
			ThisSum = 0;
			for(k = i; k <= j; k++)
				ThisSum += A[k];
			if(ThisSum > MaxSum)
				MaxSum = ThisSum;
		}
	}
	return MaxSum;
}

算法二:撤销算法一的一个for循环,运行时间O(N2)

代码:

int MaxSubsequenceSum(const int A[], int N)
{
	int ThisSum, MaxSum, i,j,k;

	MaxSum = 0;
	for(i = 0; i < N; i++)
	{
		ThisSum = 0;
		for(j = i; j < N; j++)
		{
			ThisSum += A[j];

			if(ThisSum > MaxSum)
				MaxSum = ThisSum;
		}
	}
	return MaxSum;
}


 

算法三:分治算法,相对复杂度的O(NlogN)解法

              把问题分成两个大致相等的子问题,然后递归的对它们求解,这是“分”部分。“治”阶段将两个子问题的解合并到一起并可能再做一些少量的附加工作,最后得到整个问题的解。

        在本题中,最大子序列和可能在三处出现。或者整个出现在输入数据的左半部分,或者整个出现在右半部分,或者跨越输入数据的中部从而占据左右两半部分。前两种情况可以递归求解, 第三种情况的最大和可以通过求出前半部分的最大和(从前半部分的最后一个元素开始查找,必须包含最后一个元素的序列)以及后半部分的最大和(包含后半部分的第一个元素)而得到。然后这两个和加在一起。

代码:

int Max3(int Left, int Right, int Center)
{
	cout<<"Left = "<<Left<<'\t'
		<<"Right = "<<Right<<'\t'
		<<"Center = "<<Center<<endl;

	if(Left > Right)
	{
		if(Left > Center)
			return Left;
		else
			return Center;
	}
	else
		if(Right > Center)
			return Right;
		else
			return Center;
}

static int MaxSubSum(const int A[], int Left, int Right)
{
	int MaxLeftSum, MaxRightSum;
	int MaxLeftBorderSum, MaxRightBorderSum;
	int LeftBorderSum, RightBorderSum;
	int Center, i;

	if(Left == Right)
		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);

	/*
	* 处理在Center两边交叉的元素可能构成的最大子序列和的可能
	* 求出左半部分从Center元素开始,向左寻找子序列的最大和 MaxLeftBorderSum
	* 求出有半部分从Center + 1开始的,向右寻找子序列的最大和 MaxRightBorderSum
	* 然后将 MaxLeftBorderSum + MaxRightBorderSum 就是在Center两边交叉元素可能构成的最大子序列的和
	*/

	MaxLeftBorderSum = 0;
	LeftBorderSum = 0;
	for(i = Center; i >= Left; i--)
	{
		LeftBorderSum += A[i];
		if(LeftBorderSum > 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);
}


 

算法四:直接判断,若前一个子序列的和小于 0, 则按和为0计算

代码:

int MaxSubsequenceSum(const int A[], int N)
{
	int ThisSum, MaxSum, i;

	ThisSum = MaxSum = 0;
	for(i = 0; i < N; i++)
	{
		ThisSum += A[i];

		if(ThisSum > MaxSum)
			MaxSum = ThisSum;
		else
			if(ThisSum < 0)
				ThisSum = 0;
	}
	return MaxSum;
}


补充:当所有元素全是负数时要求也是求出最大的和,应该改成这样:


 

int max_sub_array_sum2(int* array, int len)
{
	if(array == NULL || len < 0)
		exit(1);

	int max_sum = array[0];
	int cur_sum = array[0];

	for(int i=1; i < len; i++)
	{
		cur_sum += array[i];

		if(cur_sum < array[i])
		{
			cur_sum = array[i];
		}
	   
		if(cur_sum > max_sum)
		{
			max_sum = cur_sum;
		}
	}

	return max_sum;
}


 

 

你可能感兴趣的:(最大子序列和问题 分治算法)