ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

数据结构(一)基本概念 —— 编程作业 01:最大子列和问题

2021-07-05 14:04:19  阅读:190  来源: 互联网

标签:01 return 子列 int ThisSum 数据结构 MaxSum left


数据结构系列内容的学习目录 → \rightarrow →浙大版数据结构学习系列内容汇总

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

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

  • 数据1:与样例等价,测试基本正确性;
  • 数据2: 1 0 2 10^{2} 102个随机整数;
  • 数据3: 1 0 3 10^{3} 103个随机整数;
  • 数据4: 1 0 4 10^{4} 104个随机整数;
  • 数据5: 1 0 5 10^{5} 105个随机整数。

  输入格式: 输入第1行给出正整数K (≤100000);
        输入第2行给出K个整数,其间以空格分隔。

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

  输入样例:

6
-2 11 -4 13 -5 -2

  输出样例:

20

  解题思路:数据结构(一)—— 基本概念的第3节(应用实例:最大子列和问题)。

  代码实现:

#include<iostream>
using namespace std;

// 算法1:确定子列的首部和尾部,再遍历累加,时间复杂度为O(n^3)
int MaxSubseqSum1(int a[], int n)
{
	int ThisSum, MaxSum = 0;
	for (int i = 0; i < n; i++)  //i为子列左端位置
	{
		for (int j = 0; j < n; j++)  //j是子列右端位置
		{
			ThisSum = 0;  //ThisSum是从a[i]到a[j]的子列和
			for (int k = i; k <= j; k++)
			{
				ThisSum += a[k];
			}
			if (ThisSum > MaxSum)  //如果刚得到的这个子列和更大,则更新结果
			{
				MaxSum = ThisSum;
			}
		}
	}
	return MaxSum;
}

//算法2:确定子列的首部,逐个累加,时间复杂度为O(n^2)
int MaxSubseqSum2(int a[], int n)
{
	int ThisSum, MaxSum = 0;
	for (int i = 0; i < n; i++)  //i为子列左端位置
	{
		ThisSum = 0;  //ThisSum是从a[i]到a[j]的子列和
		for (int j = i; j < n; j++)  //j是子列右端位置
		{
			ThisSum += a[j];
			if (ThisSum > MaxSum)  //如果刚得到的这个子列和更大,则更新结果
			{
				MaxSum = ThisSum;
			}
		}
	}
	return MaxSum;
}

//算法3:分而治之,递归分成两份,分别求每个分割后最大子列和,时间复杂度为O(nlogn)
//返回左边最大子列和、右边最大子列和、横跨划分边界的最大子列和三者中最大值
int MaxSum(int A, int B, int C)
{
	return (A > B) ? ((A > C) ? A : C) : ((B > C) ? B : C);
}
//分治
int DivideAndConquer(int a[], int left, int right)
{
	if (left == right) 	//递归结束条件:子列只有一个数字
	{
		if (a[left] > 0)  // 当该数为正数时,最大子列和为其本身
		{
			return a[left];
		}
		return 0;	// 当该数为负数时,最大子列和为 0
	}

	//分别递归找到左右最大子列和
	int mid = left + (right - left) / 2;  //利用left+(right - left)/2求mid是为了防止整数溢出问题
	int MaxLeftSum = DivideAndConquer(a, left, mid);
	int MaxRightSum = DivideAndConquer(a, mid + 1, right);

	//再分别找左右跨界最大子列和
	int MaxLeftBorderSum = 0;
	int LeftBorderSum = 0;
	for (int i = mid; i >= left; i--)  //应该从边界出发向左边找
	{
		LeftBorderSum += a[i];
		if (LeftBorderSum > MaxLeftBorderSum)
			MaxLeftBorderSum = LeftBorderSum;
	}
	int MaXRightBorderSum = 0;
	int RightBorderSum = 0;
	for (int i = mid + 1; i <= right; i++)  // 从边界出发向右边找
	{
		RightBorderSum += a[i];
		if (RightBorderSum > MaXRightBorderSum)
			MaXRightBorderSum = RightBorderSum;
	}

	//最后返回分解的左边最大子列和,右边最大子列和,和跨界最大子列和三者中最大的数
	return MaxSum(MaxLeftSum, MaxRightSum, MaXRightBorderSum + MaxLeftBorderSum);
}
int MaxSubseqSum3(int a[], int n)
{
	return DivideAndConquer(a, 0, n - 1);
}

//算法4:在线处理,直接累加,如果累加到当前的和为负数,置当前值或0,时间复杂度为 O(n)
int MaxSubseqSum4(int a[], int n)
{
	int ThisSum = 0;
	int MaxSum = 0;
	for (int i = 0; i < n; i++)
	{
		ThisSum += a[i];  //向右累加
		if (ThisSum < 0)  //如果刚得到的这个子列和为负,则不能使后面的部分和增大,抛弃
		{
			ThisSum = 0;
		}
		else if (ThisSum > MaxSum)  //如果刚得到的这个子列和更大,则更新结果
		{
			MaxSum = ThisSum;
		}
	}
	return MaxSum;
}

int main() {
	int n;
	int a[100000 + 5];
	cin >> n; 
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
	}
	//算法1
	//int MaxSum1 = MaxSubseqSum1(a, n);
	//cout << MaxSum1 << endl;

	//算法2
	//int MaxSum2 = MaxSubseqSum2(a, n);
	//cout << MaxSum2 << endl;

	//算法3
	//int MaxSum3 = MaxSubseqSum3(a, n);
	//cout << MaxSum3 << endl;

	//算法4
	int MaxSum4 = MaxSubseqSum4(a, n);
	cout << MaxSum4 << endl;

	system("pause");

	return 0;
}

  测试: 输入样例的测试效果如下图所示。

在这里插入图片描述
  时间复杂度分析: 在某台机器上四种算法在不同输入规模时的运行时间比较结果如下图所示。

在这里插入图片描述
  可以看出第4种算法是最好的,当n=100,000时,仍可以在小于1秒的时间内得到运行结果。

 

标签:01,return,子列,int,ThisSum,数据结构,MaxSum,left
来源: https://blog.51cto.com/u_15178976/2979819

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有