浙江大学-陈越-数据结构-01-复杂度1 最大子列和问题 可通过C语言代码完全版(整合全部四种方法)

本文介绍了一种计算整数序列中最大子列和的算法,并提供了三种实现方法:暴力解法、分而治之法及在线处理法。通过实例演示了如何找出序列中拥有最大和的连续子列。

题目如下:
给定K个整数组成的序列{ N​1 , N​2​​ , …, NK},“连续子列”被定义为{ N​i, N​i+1, …, Nj},其中 1≤i≤j≤K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。

本题旨在测试各种不同的算法在各种数据情况下的表现。各组测试数据特点如下:

数据1:与样例等价,测试基本正确性;
数据2:102个随机整数;
数据3:103个随机整数;
数据4:104个随机整数;
数据5:105个随机整数;
输入格式:
输入第1行给出正整数K (≤100000);第2行给出K个整数,其间以空格分隔。

输出格式:
在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。

输入样例:
6
-2 11 -4 13 -5 -2
输出样例:
20

#include <stdio.h>

#define MaxN 100000
//在visual stdio 2019下需要下面这句话,粘贴到拼题A时需注释掉它
//#pragma warning( disable : 4996)

//a为传入数组名,K为数组长度

//1方法为暴力解法(对应视频中的解法1和2)
int MaxSeqSum1(int a[],int K);

//2方法为分而治之法
int Max3(int a, int b, int c);
int MaxSeqSum2(int a[], int K);
int DivideAndConquer(int a[], int left, int right);

//3方法为在线处理法
int MaxSeqSum3(int a[], int K);

int main()
{
	int t;
	int N;
	scanf("%d", &N);
	int test[MaxN];
	for (t = 0; t <= N - 1; t++) {
		scanf("%d", &test[t]);
	}

	//需要改变方法时将这的3改为1或2就行
	printf("%d",MaxSeqSum3(test, N)); 

	return 0;
}

//1方法为暴力解法
int MaxSeqSum1(int a[], int K){
	int MaxSum = 0;
	for (int j = 0; j <= K-1; j++) {
		int ThisSum = 0;
		for (int k = j; k <= K-1; k++) {
			ThisSum = ThisSum + a[k];
				if (ThisSum > MaxSum) {
					MaxSum = ThisSum;
			}
		}
	}

	return MaxSum;
}

//2方法为分而治之法
int MaxSeqSum2(int a[], int K) {
	return DivideAndConquer(a, 0, K-1);
}

int Max3(int a, int b, int c) {
	int max;
	
	if (a > b)
		max = a;
	else
		max = b;

	if (max > c)
		max = max;
	else
		max = c;

	return(max);
}

int k = 0;
int DivideAndConquer(int a[], int left, int right) {
	int MaxLeftSum;
	int MaxRightSum;
	int MaxCenterSum;

	int LeftBorderSum = 0;
	int RightBorderSum = 0;
	int MaxLeftBorderSum = 0;
	int MaxRightBorderSum= 0;

	int center = (left + right) / 2;

	//递归的终止条件
	if (left == right) {
		if (a[left] >= 0)
			return a[left];
		else
			return 0;
	}
	
	//分:递归求左右的最大子列和
	MaxLeftSum = DivideAndConquer(a, left, center);
	MaxRightSum = DivideAndConquer(a, center + 1, right);

	//求跨越边界的最大子列和
	for (int i = 0; i <= center - left; i++) {
		LeftBorderSum = a[center - i] + LeftBorderSum;
		if (LeftBorderSum > MaxLeftBorderSum)
			MaxLeftBorderSum = LeftBorderSum;
	}

	for (int j = 1; j <= right - center; j++) {
		RightBorderSum = a[center + j] + RightBorderSum;
		if (RightBorderSum > MaxRightBorderSum)
			MaxRightBorderSum = RightBorderSum;
	}

	MaxCenterSum = MaxLeftBorderSum + MaxRightBorderSum;

	k = k + 1;
	//printf("Left:%d Center:%d Right:%d 第%d次返回结果:%d\n", left, center, right, k, Max3(MaxCenterSum, MaxLeftSum, MaxRightSum));
	
	return Max3(MaxCenterSum, MaxLeftSum, MaxRightSum);
}

//3方法为在线处理法
int MaxSeqSum3(int a[], int K) {
	int ThisSum = 0;
	int MaxSum = 0;
	for (int i = 0; i <= K - 1; i++) {
		ThisSum = ThisSum + a[i];
		if (ThisSum > MaxSum)
			MaxSum = ThisSum;
		else if (ThisSum < 0)
			ThisSum = 0;
	}
	return MaxSum;
}

提交结果:
在这里插入图片描述
需要注意的是在自己编函数时一定要注意要用标准的输入输出,否则不会显示答案正确(这部分在首页的课程介绍里有讲到)

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值