最大子序列求和问题

最大子序列求和问题

问题描述

给定整数\(A_1\)\(A_2\),..., \(A_N\)(可能有负数),求\(\sum_{k=i}^jA_k\)的最大值(为方便起见,如果所有整数均为负数,则最大子序列和为0)。

求解

算法1:

int max_sub_sum(const int A[], int N)
{
	int sum, maxsum,i,j,k;
	maxsum = 0;
	for(i = 0; i<N; i++){
		for(j = i; j<N; j++){
			//求A[i]~A[j]的和
			sum = 0;
			for(k = i; k<j; k++){
				sum += A[k];
			}
			if(sum > maxsum)
				maxsum = sum;
		}
	}
	
	return maxsum;
}

算法1的时间复杂度为\(O(N^3)\)

算法2:

int max_sub_sum2(const int A[], int N)
{
	int sum, maxsum, i, j;
	maxsum = 0;
	for(i = 0; i<N; i++){
		sum = 0;
		for(j = i; j<N; j++){
			sum += A[j];
			if(sum > maxsum){
				maxsum = sum;
			}
		}
	}
	
	return maxsum;
}

算法2的复杂度为\(O(N^3)\),与算法1相比,算法2减少了一个内层循环

算法3

int maxsubsum(const int A[], int left, int right)
{
	//采用分治法求解
	if(left > right){
		printf("error: left>right!\n");
		return -1;
	} else if(left == right) {
		if(A[left]>=0) {
			return A[left];
		} else {
			return 0;
		}
	} else {
		int maxleftsum, maxrightsum, maxleftborder, maxrightborder, maxcrosssum, tmpsum;
		int center, i;
		center = (left+right)/2;
		maxleftsum = maxsubsum(A, left, center);
		maxrightsum = maxsubsum(A, center+1, right);
		
		tmpsum = maxleftborder = 0;
		for(i = center; i>=left; i--){
			tmpsum += A[i];
			if(tmpsum > maxleftborder) {
				maxleftborder = tmpsum;
			}
		}
		tmpsum = maxrightborder = 0;
		for(i = center+1; i<=right; i++) {
			tmpsum += A[i];
			if(tmpsum > maxrightborder) {
				maxrightborder = tmpsum;
			}
		}
		maxcrosssum = maxleftborder+maxrightborder;
		
		if(maxcrosssum >= maxleftsum && maxcrosssum >= maxrightsum)
			return maxcrosssum;
		if(maxleftsum >= maxcrosssum && maxleftsum >= maxrightsum)
			return maxleftsum;
		if(maxrightsum >= maxcrosssum && maxrightsum >= maxleftsum)
			return maxrightsum;
	}
}
int max_sub_sum3(const int A[], int N)
{
	return maxsubsum(A, 0, N-1);
}

算法3用了分治法来求解,以序列的中间为分界线,最大子序列要么再左边一半,要么再右边一半,要么穿过中间,只要分别求左边一半最大子序列、右边一半最大子序列和穿过中间爱的最大子序列,最后从它们之间选出最大的即是整个序列的最大子序列,该分治算法的时间复杂度为\(O(N\log N)\)

算法4

int max_sub_sum4(const int A[], int N)
{
	int sum, maxsum, i;
	sum = maxsum = 0;
	for(i = 0;i<N; i++){
		sum += A[i];
		if(sum > maxsum) {
			maxsum = sum;
		} else if (sum < 0) {
			sum = 0;
		}
	}
	
	return maxsum;
}

算法4的时间复杂度为\(O(N)\),该算法只要读一遍输入序列就可以算出最大子序列和

实验

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

int max_sub_sum(const int A[], int N)
{
	int sum, maxsum,i,j,k;
	maxsum = 0;
	for(i = 0; i<N; i++){
		for(j = i; j<N; j++){
			//求A[i]~A[j]的和
			sum = 0;
			for(k = i; k<j; k++){
				sum += A[k];
			}
			if(sum > maxsum)
				maxsum = sum;
		}
	}
	
	return maxsum;
}

int max_sub_sum2(const int A[], int N)
{
	int sum, maxsum, i, j;
	maxsum = 0;
	for(i = 0; i<N; i++){
		sum = 0;
		for(j = i; j<N; j++){
			sum += A[j];
			if(sum > maxsum){
				maxsum = sum;
			}
		}
	}
	
	return maxsum;
}

int maxsubsum(const int A[], int left, int right)
{
	//采用分治法求解
	if(left > right){
		printf("error: left>right!\n");
		return -1;
	} else if(left == right) {
		if(A[left]>=0) {
			return A[left];
		} else {
			return 0;
		}
	} else {
		int maxleftsum, maxrightsum, maxleftborder, maxrightborder, maxcrosssum, tmpsum;
		int center, i;
		center = (left+right)/2;
		maxleftsum = maxsubsum(A, left, center);
		maxrightsum = maxsubsum(A, center+1, right);
		
		tmpsum = maxleftborder = 0;
		for(i = center; i>=left; i--){
			tmpsum += A[i];
			if(tmpsum > maxleftborder) {
				maxleftborder = tmpsum;
			}
		}
		tmpsum = maxrightborder = 0;
		for(i = center+1; i<=right; i++) {
			tmpsum += A[i];
			if(tmpsum > maxrightborder) {
				maxrightborder = tmpsum;
			}
		}
		maxcrosssum = maxleftborder+maxrightborder;
		
		if(maxcrosssum >= maxleftsum && maxcrosssum >= maxrightsum)
			return maxcrosssum;
		if(maxleftsum >= maxcrosssum && maxleftsum >= maxrightsum)
			return maxleftsum;
		if(maxrightsum >= maxcrosssum && maxrightsum >= maxleftsum)
			return maxrightsum;
	}
}
int max_sub_sum3(const int A[], int N)
{
	return maxsubsum(A, 0, N-1);
}

int max_sub_sum4(const int A[], int N)
{
	int sum, maxsum, i;
	sum = maxsum = 0;
	for(i = 0;i<N; i++){
		sum += A[i];
		if(sum > maxsum) {
			maxsum = sum;
		} else if (sum < 0) {
			sum = 0;
		}
	}
	
	return maxsum;
}

int main()
{
	int A[]={-2, 11, -4, 13, -5, -2};
	
	printf("max_sub_sum = %d\n", max_sub_sum(A, sizeof(A)/sizeof(int)));
	printf("max_sub_sum = %d\n", max_sub_sum2(A, sizeof(A)/sizeof(int)));
	printf("max_sub_sum = %d\n", max_sub_sum3(A, sizeof(A)/sizeof(int)));
	printf("max_sub_sum = %d\n", max_sub_sum4(A, sizeof(A)/sizeof(int)));

	return 0;
}
posted @ 2018-06-23 17:30  main_c  阅读(367)  评论(0)    收藏  举报