使用分治法解最大连续子序列和问题

    俺是菜鸟了解一下,这是我在算法学习中的一些想法,如果有写的不好的还请谅解,欢迎学习交流_(:3」∠)_

    问题:有长度为n的整数序列,求一段连续的子序列,要求该子序列的和为最大,并求出最大值。

    用分治法解决最大子序列和问题使用的是递归,它的思想是:

1.将一个长度为n的序列,一分为二变为两个长度为n/2的子序列,继续将子序列们一分为二,直到每个子序列只含有1个整数。

2.此时问题已经足够小,“最大子序列和”有以下三种情况:左边序列的最大子序列和、右边序列的最大子序列和和处在中间位置上的最大子序列和,我们通过比较,得到三者中的最大值。

3.再将这些“小问题”合并,使用同样的比较方法逐步向上合并这些“左右序列”,直到得到整个序列的最大子序列和,解决问题。


    在这个问题中,分为两种情况:1.序列含有正整数;2.序列不含正整数。我的想法是可以对这两种情况分别使用对应的函数。

    第一种情况,序列含有正整数,算法的时间复杂度为O(nlog(n)):

int MaxSubseqSum(int a[],int left,int right)
{
	int maxLeftSum,maxRightSum,maxMidSum;
	int maxLeftBorderSum,LeftBorderSum;
	int maxRightBorderSum,RightBorderSum;
	int mid;
	int i;
	if(left==right)	//递归出口,子序列只有一个元素时
		return a[left];
	mid=(left+right)/2;	//求中间位置
	maxLeftSum=MaxSubseqSum(a,left,mid);	//求左边序列的最大子序列和
	maxRightSum=MaxSubseqSum(a,mid+1,right);	//求右边序列的最大子序列和
	maxLeftBorderSum=0;
	LeftBorderSum=0;
	for(i=mid;i>=left;i--)	//从中间位置向左找靠边界的最大子序列
	{
		LeftBorderSum+=a[i];
		if(LeftBorderSum>maxLeftBorderSum)
			maxLeftBorderSum=LeftBorderSum;
	}
	maxRightBorderSum=0;
	RightBorderSum=0;
	for(i=mid+1;i<=right;i++)	//从中间位置向右找靠边界的最大子序列
	{
		RightBorderSum+=a[i];
		if(RightBorderSum>maxRightBorderSum)
			maxRightBorderSum=RightBorderSum;
	}
	maxMidSum=maxLeftBorderSum+maxRightBorderSum;	//得到处在中间位置上的最大子序列和
	return max3(maxLeftSum,maxRightSum,maxMidSum);
}

  第二种情况,序列不含正整数,可以改为使用分治法取序列中最大的数,算法的时间复杂度为O(log(n))

int MaxNum(int a[],int left,int right)
{
	int maxLeft,maxRight;
	int mid;
	if(left==right)
		return a[left];
	mid=(left+right)/2;
	maxLeft=MaxNum(a,left,mid);
	maxRight=MaxNum(a,mid+1,right);
	return maxLeft>maxRight?maxLeft:maxRight;
}

完整运行代码:

#include
#define MAXSIZE 100

int max3(int a,int b,int c)
{
	if(a>b) return a>c?a:c;
	else return b>c?b:c;
}

int MaxSubseqSum(int a[],int left,int right)
{
	int maxLeftSum,maxRightSum,maxMidSum;
	int maxLeftBorderSum,LeftBorderSum;
	int maxRightBorderSum,RightBorderSum;
	int mid;
	int i;
	if(left==right)	//递归出口,子序列只有一个元素时
		return a[left];
	mid=(left+right)/2;	//求中间位置
	maxLeftSum=MaxSubseqSum(a,left,mid);	//求左边序列的最大子序列和
	maxRightSum=MaxSubseqSum(a,mid+1,right);	//求右边序列的最大子序列和
	maxLeftBorderSum=0;
	LeftBorderSum=0;
	for(i=mid;i>=left;i--)	//从中间位置向左找靠边界的最大子序列
	{
		LeftBorderSum+=a[i];
		if(LeftBorderSum>maxLeftBorderSum)
			maxLeftBorderSum=LeftBorderSum;
	}
	maxRightBorderSum=0;
	RightBorderSum=0;
	for(i=mid+1;i<=right;i++)	//从中间位置向右找靠边界的最大子序列
	{
		RightBorderSum+=a[i];
		if(RightBorderSum>maxRightBorderSum)
			maxRightBorderSum=RightBorderSum;
	}
	maxMidSum=maxLeftBorderSum+maxRightBorderSum;	//得到处在中间位置上的最大子序列和
	return max3(maxLeftSum,maxRightSum,maxMidSum);
}

int MaxNum(int a[],int left,int right)
{
	int maxLeft,maxRight;
	int mid;
	if(left==right)
		return a[left];
	mid=(left+right)/2;
	maxLeft=MaxNum(a,left,mid);
	maxRight=MaxNum(a,mid+1,right);
	return maxLeft>maxRight?maxLeft:maxRight;
}

void main()
{
	int a[MAXSIZE];
	int count=0;
	int i,n;
	printf("序列长度:");
	scanf("%d",&n);
	printf("输入整数序列:");
	for(i=0;i





你可能感兴趣的:(C语言算法)