【经典算法】 最大子段和

原创作品,转载请标明http://blog.csdn.net/xiejingfa/article/details/48439925


问题

给定一个大小为n的整数序列a[0],a[1],...a[n - 1],找出该序列子段和的最大值,即 max (a[i]+a[i+1]+...+a[j]) 0<=i<=j<=n-1)。

比如序列[-2,2,-3,4,- 1,2,1,-5,3],最大子段和为6,对应的子数组为[4,-1,2,1]。


求解方法

1、简单算法

/** 简单算法(暴力破解):即枚举i和i,求arr[i]和arr[j]之间的元素和。
	时间复杂度为O(n^3)。
*/
int maxSubArray1(int* arr, int n)
{
	int maxSum = INT_MIN, tmpSum = 0;
	for (int i = 0; i < n; i++)
	{
		for (int j = i + 1; j < n; j++)
		{
			tmpSum = 0;
			for (int k = i; k <= j; k++)
				tmpSum += arr[k];
			maxSum = std::max(maxSum, tmpSum);
		}
	}
	return maxSum;
}

2、改进的简单算法

/** 在算法1中,最内层for循环用来计算arr[i]和arr[j]之间的元素和。我们可以引入一个临时数组
	保存预先算好的各个子段和。这样就把时间复杂度降为O(n^2)。
*/
int maxSubArray2(int* arr, int n)
{
	// 预先计算好字段和
	int* p = new int[n];
	int tmp = 0;
	for (int m = 0; m < n; m++)
	{
		tmp += arr[m];
		p[m] = tmp;
	}

	int maxSum = INT_MIN, tmpSum = 0;
	for (int i = 0; i < n; i++)
	{
		for (int j = i + 1; j < n; j++)
		{
			tmpSum = p[j] - p[i]; // p[j] - p[i]表示arr[i]和arr[j]之间的元素和
			maxSum = std::max(maxSum, tmpSum);
		}
	}
	delete[] p;

	return maxSum;
}

3、分治法

/** 分治算法:将给定的序列arr[1..n]分成长度相等的两段arr[1...n/2]和arr[n/2+1...n],分别求出这两段的最大子段和。
	则该给定序列的最大子段有三种情况:
	(1)、和arr[1...n/2]的最大子段和一致;
	(2)、和arr[n/2+1...n]的最大子段和一致;
	(3)、最大子段和包含两个部分,分别位于arr[1...n/2]和arr[n/2+1...n]中。
	该算法的时间复杂度为O(nlogn)。
*/
int maxSubArray3(int* arr, int left, int right)
{
	int sum = INT_MIN;
	if (left == right)
		return arr[left] >= 0 ? arr[left] : 0;
	else 
	{
		int mid = (left + right) / 2;
		int leftSum = maxSubArray3(arr, left, mid);
		int rightSum = maxSubArray3(arr, mid + 1, right);

		int s1 = INT_MIN, lefts = 0;
		for (int i = mid; i >= left; i--)
		{
			lefts += arr[i];
			s1 = std::max(lefts, s1);
		}

		int s2 = INT_MIN, rights = 0;
		for (int j = mid + 1; j <= right; j++)
		{
			rights += arr[j];
			s2 = std::max(rights, s2);
		}

		sum = s1 + s2;
		if (sum < leftSum)
			sum = leftSum;
		if (sum < rightSum)
			sum = rightSum;
	}
	return sum;
}

4、动态规划算法

/**	动态规划算法:设b[j]的值为以arr[j]结尾的最大子段和,即
	b[j] = max{arr[i] +...+ arr[j]},其中0<=i<=j,0<=j<n。整个序列的最大子段和为max(b[j])。
	由b[j]的定义可知,当b[j-1]>0时,b[j] = b[j - 1] + a[j],否则b[j] = a[j]。
	所以动态规划递归式为:b[j] = max{b[j - 1] + a[j], a[j]}, 0<=j<n。
	时间复杂度为O(n)。
*/
int maxSubArray4(int* arr, int n)
{
	int maxSum = INT_MIN, tmpSum = 0;
	for (int i = 0; i < n; i++)
	{
		if (tmpSum >= 0)
			tmpSum += arr[i];
		else 
			tmpSum = arr[i];
		maxSum = std::max(maxSum, tmpSum);
	}
	return maxSum;
}



你可能感兴趣的:(最大子段和)