题目 2 最大子序列和问题

介绍了一种求解整型数组中最大子数组和的算法,包括O(n^2)复杂度的双层循环方法和更高效的O(n)复杂度的单层循环方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:输入一个整型的数组,数组里有可能有正数也可能有负数。数组中连续的一个或多个整数组成该数组的一个子数组,

每个子数组的所有元素的和称为子数组的和。求该数组的所有子数组的和的最大值。


分析:如果数据不多,可以用简单的方式遍历所有可能的子数组的和,求出最大的即可。用两层循环可以给出一个O(n^2)的算法,如下所示:

/*
 * @func:	max_sub_sum_n2
 * @desc:	Given a array of integer, 
 * 			return the max of its all sub array sums
 * 			in an O(n^2) time complexity
 * @param:
 * 			v: input integer array
 *
 * @retval:	max sub sum
 */
int max_sub_sum_n2(const std::vector<int>& v) 
	throw (std::out_of_range)
{
	if (v.empty()) throw std::out_of_range("Array is empty!");

	typedef std::vector<int>::size_type vsize_t;
	vsize_t end_pos = v.size();

	vsize_t start_pos = 0;
	int max = v[start_pos];

	for (; start_pos != end_pos; start_pos++) {
		int sum = 0;
		for (vsize_t iter = start_pos; iter != end_pos; iter++) {
			sum += v[iter];
			if (max < sum) max = sum;
		}
	}

	return max;
}

该算法是一个O(n^2)的算法,我们可以用它来做一个结果的对比验证方式。 下面进一步考虑O(n)的算法。

首先我们考虑一个例子。假设输入的数组为4, -3, -2, 7, -1, 2, 4。 该数组的和最大的子数组为7, -1, 2, 4。

让我们按照上面的算法执行一遍来看一下:

首先,i = 0, 此时计算所有从A0开始的子数组的和

1, j = 0; 所以 sum = 4, max = 4;  这时候子数组为 A0

2, j = 1;此时,sum = 4 + (-3) = 1, max = 4;  这时候子数组为 A0, A1

3, j = 2;此时,sum = 1 + (-2) = -1, max = 4; 这时候子数组为A0, A1, A2

此时,sum = -1 已经小于0了。 在i = 0的剩下的循环中, 所有以A0开始的子数组的和都不会超过相应的从A3开始的子数组的和。因此,再将j继续循环下去是没有意义的。

故可以直接将i推进到 i + 1而无须继续进行剩余的循环。

当推进 i 的时候,我们进一步考虑。由于在上面的循环中,在j = 2之前,所有以A0...Aj 子数组的和均为正数,A0 ... A2是第一个和为负的数组。故,任何以Ak (k = 1 .. 2)开头的

数组都不会比加上A0 ... Ak-1 的子数组的和大。考虑到这一点,我们可以将i继续从i + 1推进到j + 1. 

因此,当第一层循环的和为负值了之后,我们可以直接将i推进到为负值的下一个位置,继续循环,直到循环完成整个数组。这样,两层循环变为 1层循环,复杂度也降低为O(n)。代码如下:

/*
 * @func:	max_sub_sum_n2
 * @desc:	Given a array of integer, 
 * 			return the max of its all sub array sums
 * 			in an O(n) time complexity
 * @param:
 * 			v: input integer array
 *
 * @retval:	max sub sum
 */
int max_sub_sum_n(const std::vector<int>& v) 
	throw (std::out_of_range)
{
	if (v.empty())
		throw std::out_of_range("Array is empty");
	
	typedef std::vector<int>::size_type vsize_t;
	vsize_t end_pos = v.size();
	vsize_t start_pos = 0;
	int max = v[start_pos];
	int sum = 0;

	for (vsize_t iter = start_pos; iter != end_pos; iter++) {
		sum += v[iter];
		if (max < sum) max = sum;
		if (sum <= 0) sum = 0;
	}
	return max;
}

注意,这里面其实没有必要考虑过多0的问题。只要将max的初始化为数组第一个元素的值即可处理全为负数的情况。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值