最大子列和 C语言 4种方法

题目:最大子列和

问题描述:在一个一维数组中找到一个连续的子数列,使该子数列的和最大,输出该和的值

输入:数组元素个数n,数组各元素

输出:最大子列和

(以int类型数组为例)

目录

方法1

方法2

方法3:分治法

方法4:在线处理

检验

 完整代码


方法1

时间复杂度:O(N³)

int maxsubsetsum1(int A[], int n)
{
	int thissum, maxsum = A[0];//注意:maxsum的初值应当是其可能的任一值,但不可随意赋值
	for (int i = 0; i < n; i++)
	{
		for(int j = i; j < n; j++)
		{
			thissum = 0;
			for (int k = i; k <= j; k++)
			{
				thissum += A[k];
			}
			maxsum = maxsum >= thissum ? maxsum : thissum;
		}
	}
	return maxsum;
}

方法2

时间复杂度:O(N²)

nt maxsubsetsum2(int A[], int n)
{
	int thissum, maxsum = A[0];//注意:maxsum的初值应当是其可能的任一值,但不可随意赋值
	for (int i = 0; i < n; i++)
	{
		thissum = 0;
		for (int j = i; j < n; j++)
		{
			thissum += A[j];
			maxsum = maxsum >= thissum ? maxsum : thissum;
		}
	}
	return maxsum;
}

方法3:分治法

时间复杂度:O(N logN)

int maxsubsetsum3(int A[], int l, int r)
{
	if (l == r) //分到最后一层,直接返回
	{  
		return A[l];
	}
	int mid = (l + r) / 2; //取中间位置

	int maxleftsum = maxsubsetsum3(A, l, mid); //求左组的最大子列和
	int maxrightsum = maxsubsetsum3(A, mid + 1, r); //求右组的最大子列和

	//该子列元素同时存在于左组和右组,即该子列中含有A[mid]和A[mid+1]
	//注意:初值应当是其可能的任一值,但不可随意赋值
	int maxleftmidsum = A[mid];
	int leftmidsum = 0;
	int maxrightmidsum = A[mid + 1];
	int rightmidsum = 0;
	for (int i = mid; i >= l; i--) //该子列左部分的和
	{ 
		leftmidsum += A[i];
		maxleftmidsum = maxleftmidsum < leftmidsum ? leftmidsum : maxleftmidsum;
	}

	for (int i = mid + 1; i <= r; i++) //该子列右部分的和
	{ 
		rightmidsum += A[i];
		maxrightmidsum = maxrightmidsum < rightmidsum ? rightmidsum : maxrightmidsum;
	}

	return max3(maxleftsum, maxrightsum , maxleftmidsum + maxrightmidsum);//左组最大子列和,右组最大子列和,包含A[mid]和A[mid+1]的最大子列和
}

int max3(int a, int b, int c)  //求三者中的最大值
{
	if (a < b)a = b;
	if (a < c)a = c;
	return a;
}

方法4:在线处理

时间复杂度:O(N)

int maxsubsetsum4(int A[], int n)
{
	int thissum=0, maxsum=A[0];
	for (int i = 0; i < n; i++)
	{
		thissum += A[i];  
		if (thissum > maxsum)
		{
			maxsum = thissum;
		}
		else if (thissum < 0)
		{
			thissum = 0;
		}
	}
	return maxsum;
}

检验

最后,加上main函数,输入数据,调用函数进行检验

int main() 
{
	int n;
	while (scanf("%d", &n) == 1 && n != 0)//当输入n为0时结束程序
	{
		int num[100];
		for (int i = 0; i < n; i++)
		{
			cin >> num[i];
		}
		printf("maxsubsetsum1= %d\n", maxsubsetsum1(num, n));
		printf("maxsubsetsum2= %d\n", maxsubsetsum2(num, n));
		printf("maxsubsetsum3= %d\n", maxsubsetsum3(num, 0, n - 1));
		printf("maxsubsetsum4= %d\n", maxsubsetsum4(num, n));
	}
	return 0;
}

一个很好的方法是:当用多种算法解决同一问题时,若输出一致,则方法大抵正确

注意:要选用一些刁钻数据(如全为正数、全为负数、正数负数都有)

附上运行结果:

 完整代码

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;

int maxsubsetsum1(int A[], int n);
int maxsubsetsum2(int A[], int n);
int maxsubsetsum3(int A[], int l, int r);
int maxsubsetsum4(int A[], int n);
int max3(int a, int b, int c);

int main()
{
	int n;
	while (scanf("%d", &n) == 1 && n != 0)//当输入n为0时结束程序
	{
		int num[100];
		for (int i = 0; i < n; i++)
		{
			cin >> num[i];
		}
		printf("maxsubsetsum1= %d\n", maxsubsetsum1(num, n));
		printf("maxsubsetsum2= %d\n", maxsubsetsum2(num, n));
		printf("maxsubsetsum3= %d\n", maxsubsetsum3(num, 0, n - 1));
		printf("maxsubsetsum4= %d\n", maxsubsetsum4(num, n));
	}
	return 0;
}

int maxsubsetsum1(int A[], int n)
{
	int thissum, maxsum = A[0];//注意:maxsum的初值应当是其可能的任一值,但不可随意赋值
	for (int i = 0; i < n; i++)
	{
		for(int j = i; j < n; j++)
		{
			thissum = 0;
			for (int k = i; k <= j; k++)
			{
				thissum += A[k];
			}
			maxsum = maxsum >= thissum ? maxsum : thissum;
		}
	}
	return maxsum;
}

int maxsubsetsum2(int A[], int n)
{
	int thissum, maxsum = A[0];//注意:maxsum的初值应当是其可能的任一值,但不可随意赋值
	for (int i = 0; i < n; i++)
	{
		thissum = 0;
		for (int j = i; j < n; j++)
		{
			thissum += A[j];
			maxsum = maxsum >= thissum ? maxsum : thissum;
		}
	}
	return maxsum;
}

int maxsubsetsum3(int A[], int l, int r)
{
	if (l == r) //分到最后一层,直接返回
	{  
		return A[l];
	}
	int mid = (l + r) / 2; //取中间位置

	int maxleftsum = maxsubsetsum3(A, l, mid); //求左组的最大子列和
	int maxrightsum = maxsubsetsum3(A, mid + 1, r); //求右组的最大子列和

	//该子列元素同时存在于左组和右组,即该子列中含有A[mid]和A[mid+1]
	//注意:初值应当是其可能的任一值,但不可随意赋值
	int maxleftmidsum = A[mid];
	int leftmidsum = 0;
	int maxrightmidsum = A[mid + 1];
	int rightmidsum = 0;
	for (int i = mid; i >= l; i--) //该子列左部分的和
	{ 
		leftmidsum += A[i];
		maxleftmidsum = maxleftmidsum < leftmidsum ? leftmidsum : maxleftmidsum;
	}

	for (int i = mid + 1; i <= r; i++) //该子列右部分的和
	{ 
		rightmidsum += A[i];
		maxrightmidsum = maxrightmidsum < rightmidsum ? rightmidsum : maxrightmidsum;
	}

	return max3(maxleftsum, maxrightsum , maxleftmidsum + maxrightmidsum);//左组最大子列和,右组最大子列和,包含A[mid]和A[mid+1]的最大子列和
}

int max3(int a, int b, int c)  //求三者中的最大值
{
	if (a < b)a = b;
	if (a < c)a = c;
	return a;
}

int maxsubsetsum4(int A[], int n)
{
	int thissum=0, maxsum=A[0];
	for (int i = 0; i < n; i++)
	{
		thissum += A[i];  
		if (thissum > maxsum)
		{
			maxsum = thissum;
		}
		else if (thissum < 0)
		{
			thissum = 0;
		}
	}
	return maxsum;
}

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值