算法:Maximum Subsequence Sum

Given a sequence of K integers { N​1​​, N​2​​, ..., N​K​​ }. A continuous subsequence is defined to be { N​i​​, N​i+1​​, ..., N​j​​} where 1≤i≤j≤K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.

Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.

Input Specification:

Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (≤10000). The second line contains K numbers, separated by a space.

Output Specification:

For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices iand j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.

Sample Input:

10
-10 1 2 3 4 -5 -23 3 7 -21

Sample Output:

10 1 4

最大子列求和,之前做过,但是今天在牛客网上调一个bug,调了一下午。以后对于算法题一定要好好分析考虑多种情况。

该题需要注意的是最大子列下标i,j最小:

1、最大子列后面有0,此时不应该计算 .

2、最大子列前面有0,因此最小的0算起。就是这个bug坑了我一下午。

非常简洁,但是要是不仔细分析,是很难发现问题的,查找i并不容易,我最后用的方法就是向前比较相等,一直到下标0。

3、全负、0与负数混合这两种情况需要区别。

下面是我用数组实现的源程序,通过mallo开辟合适的空间,时间复杂度是O(N),在线处理,没有使用二分法(感觉麻烦,另外就是感觉内存可能会爆):

#include <stdio.h>
#include <stdlib.h>

void SubSeq_Max(int a[], int k);
 
int main()
{
	int k,i,*a;
	while(scanf("%d",&k)!=EOF)
	{
		a = (int *)malloc(k*sizeof(int));
		for(i=0; i<k; i++)
			scanf("%d",&a[i]);
	
		SubSeq_Max(a,k);
	}

	return 0;
}

void SubSeq_Max(int a[], int k)
{
	int i,f0=0,f1=0,f=1,m=0;		/* f作为 -2 -3 0 0 与全负数标记 */ 
	int sum=0,t=0,s=0;
	for(i=0; i<k; i++)
	{
		//printf("sum=%d,t=%d,f0=%d,f1=%d\n",sum,t,f0,f1);
		sum += a[i];
		if( sum < 0)
			sum = 0;
		if( sum > t )	
		{
			t = sum;
			f1 = i;	
		}
		
		if(a[i] == 0)	/* 全负标记,f==1 ,且sum==0说明全负 */ 
		{
			f = 0;
			m = i;		/* m负数与0混合下标 */ 
		}

	}	
	s = sum > t ? sum :t;
	if( s!=0 ){			/* s==0 说明全负或负数与0混合 */ 
		/* 
		**	问题在这,如何查找f0.
		**	f0为最小的 
		*/ 
		sum = 0;
		for(i = f1; i>=0 ; i--)
		{
			sum += a[i];
			if(sum == s) 
				f0 = i;
		}
	} 
	else if( f )	/* 全负数 */ 
	{
		f0 = 0;
		f1 = k-1;
	} 
	else			/* 负数与0混合 */
	{
		f0 = m;
		f1 = m;
	}
	
	printf("%d %d %d\n",s,a[f0],a[f1]);
}

之前针对链表我也写了一份代码,但是只输出最大子列,不输出对应下边的数范围。下面是源程序

#include <stdio.h>
#include <stdlib.h>

typedef struct LNode *List;
struct LNode{
	int data;
	List next;
};

List ReadInput();
void Print(List L);
int SubSeq_Max(List L);
 
int main()
{
	List L;
	while( getchar() != EOF){
		L = ReadInput();
	//	Print(L);
		printf("%d\n",SubSeq_Max(L));
	}
	return 0;
}

List ReadInput()
{
	int K,i;
	List P,L,t;
	L = (List)malloc(sizeof(struct LNode));
	P = L;
	scanf("%d",&K);
	if( K==0 )	return NULL;
	for(i = 0; i<K; i++)
	{
		scanf("%d",&P->data);
		t = P;
		P = (List)malloc(sizeof(struct LNode));
		t->next = P;
	}
	t->next = NULL;
	free(P);
	return L;
}

void Print(List L)
{
	List P=L;
	for(; P!= NULL; P = P->next)
	{
		if(P->next != NULL)
			printf("%d ",P->data);
		else	printf("%d\n",P->data);
	}
	if(L == NULL)
		printf("NULL\n");
}

int SubSeq_Max(List L)
{
	List P;
	int sum=0,t=0;
	for(P = L; P != NULL; P = P->next)
	{
	//	printf("sum=%d,t=%d\n",sum,t);		
		sum += P->data;
		if( sum < 0)
			sum = 0;
			
		if( sum > t )
			t = sum;
	}
	return  sum > t ? sum : t;
}

 欢迎互相探讨,谢谢!

猜你喜欢

转载自blog.csdn.net/Bridge3/article/details/82532443