(三)最大子段和问题

1.概念

求数组的和最大的非空连续子数组,这样的连续的子数组称为最大子数组(maximum subarray)

2.常规方法(O^3)

/* 最大子段和问题 O^3*/
#include <iostream>
using namespace std;

//打印数组
void printArray(int *arr, int strat, int last)
{
	for (int i = strat; i <= last; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

//求最大子段和
int MaxSum(int len, int *arr, int& besti, int &bestj)
{
	int sum = 0;
	for(int i = 1; i <= len; i++)
	{
		for (int j = i; j <= len; j++)
		{
			int thissum = 0;
			for (int k = i; k <= j; k++)
			{
				thissum += arr[k];
			}
			if (thissum > sum)
			{
				sum = thissum;	//最大字段和
				besti = i;		//最大子段和开始位置
				bestj = j;		//最大子段和结束位置
			}
		}
	}
	return sum;
}

int main()
{
	int len = 0, i = 0, j = 0;
	int array[16] = { 13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7 };

	//数组长度
	len = sizeof(array) / sizeof(*array);

	//打印原始数组
	cout << "The Array is: " << endl;
	printArray(array, 0, len-1);

	//求最大子段和
	cout << "The MaxSum is: " << endl;
	cout << MaxSum(len, array, i, j) << endl;
	
	//打印最大子段
	cout << "The MaxSumArray is: " << endl;
	printArray(array, i, j);

	system("pause");
	return 0;
}
/*
The Array is:
13 -3 -25 20 -3 -16 -23 18 20 -7 12 -5 -22 15 -4 7
43
The MaxSumArray is:
18 20 -7 12
请按任意键继续. . .
*/

3.分治策略解决最大子段和问题(nlgn)

分治策略在每层递归时都有三个步骤:

A 分解原问题为若干子问题,这些子问题是原问题的规模较小的实例。

B 解决这些子问题,递归地求解各子问题。然而,若子问题的规模足够小,则直接求解。

C 合并这些子问题的解成原问题的解。

分治策略的求解分析

假设要寻找子数组A[low…high]的最大子数组。使用分治策略要将子数组划分为两个规模尽量相等的子数组。先找到中间位置mid,然后考虑求解两个子数组A[low…mid]和A[mid+1…high]。

A[low…high]的任何连续子数组A[i…j]所处的位置必然是以下三种情况之一:

A      完全位于子数组A[low…mid]中,low≤i≤j≤mid。

B      完全位于子数组A[mid+1…high],mid+1≤i≤j≤high。

C      跨越了中点,low≤i≤mid≤j≤high。

/* 分治思想下的最大子段和问题 nlgn*/
#include <iostream>
using namespace std;

//打印数组
void PrintArray(int *arr, int strat, int last)
{
	for (int i = strat; i <= last; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

//寻找最大子段和
int MaxSubSum(int *arr, int low, int high, int& bestl, int& bestr)
{
	int sum = 0, mid = 0, leftSum = 0, rightSum = 0;
	int sl = 0, sr = 0, leftS = 0, rightS = 0;
	int l = 0, r = 0;
	if (low == high)//只有一个元素
	{
		sum = arr[low];
	}
	else
	{
		mid = (low + high) / 2;//中间位置
		//分治思想
		leftSum = MaxSubSum(arr, low, mid, l, r);
		rightSum = MaxSubSum(arr, mid + 1, high, l, r);

		//左半部分最大子段和
		for (int i = mid; i >= low; i--)
		{
			leftS += arr[i];
			if (leftS > sl)
			{
				sl = leftS;
				bestl = i;
			}
		}

		//右半部分最大子段和
		for (int i = mid + 1; i <= high; i++)
		{
			rightS += arr[i];
			if (rightS > sr)
			{
				sr = rightS;
				bestr = i;
			}
		}
		sum = sl + sr;//跨越中点的最大子段和
		if (sum < leftSum)
		{
			sum = leftSum;
		}
		if (sum < rightSum)
		{
			sum = rightSum;
		}
	}
	return sum;
	
}

int main()
{
	int len = 0, l = 0, r = 0;
	int array[] = { 13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7 };

	//数组长度
	len = sizeof(array) / sizeof(*array);

	//打印原始数组
	cout << "The Array is: " << endl;
	PrintArray(array, 0, len - 1);

	//寻找最大子数组
	cout << "The MaxSum is: " << endl;
	cout << MaxSubSum(array, 0, len - 1, l, r) << endl;

	///打印最大子数组
	cout << "The MaxSumArray is: " << endl;
	PrintArray(array, l, r);

	system("pause");
	return 0;
}
/*
The Array is:
13 -3 -25 20 -3 -16 -23 18 20 -7 12 -5 -22 15 -4 7
The MaxSum is:
43
The MaxSumArray is:
18 20 -7 12
请按任意键继续. . .
*/

猜你喜欢

转载自blog.csdn.net/ailunlee/article/details/80095759
今日推荐