7、给定n个序列,求相邻的k个数之和为最大

1、问题描述:给定n个数,求相邻的k个数之和为最大。要求给出复杂度较小的一种算法

再解决这个问题前,先了解一下类似的常见问题。

2、给定一串数字(可正可负的int,放在数组Num里),要求找到起始位置start和终止位置end,使得从start位置到end位置的所有数字之和最大,返回这个最大值max

算法思想:用动态规划算法实现。

iMaxSum 为以 iNumPar[i] 终止且包含 iNumPar[i] 的最大序列的和,有:

   iMaxSum  =  iNumPar[0];

   iMaxSum  =  iMaxSum > 0 ? iMaxSum + iNumPar[i+1] : iNumPar[i+1];

   其中,i = 0,1,...

那么和iMaxSum 就是 iNumPar[0] ... iNumPar[n] 中最大的一个序列。

算法的时间复杂度为O(n)

示例代码

#include <iostream>

using namespace std;

void FindTheMaxSum(int iNumPar[], const int iSize, int &ibegin, int &iend, int &iMaxSum)
{
	ibegin = iend = 0;
	int iTemSum = iNumPar[0], iStart = 0;
	iMaxSum = iTemSum;
	for (int i = 1; i < iSize; ++i)
	{
		if (iTemSum > 0)
		{
			iTemSum = iTemSum + iNumPar[i];
		}
		else
		{
			iTemSum = iNumPar[i];
			iStart = i;
		}
		
		if (iTemSum > iMaxSum) //更新结果
		{
			iMaxSum = iTemSum;
			ibegin = iStart;
			iend = i;
		}
	}
}

int main()
{
    int ibegin = 0, iend = 0, iResult = 0, iCount = 0;
	int iNum[] = {-1, -2, -3, -4, 0, 1, 2, 3, 4, 5, -20, 40, -3};
	iCount = sizeof(iNum)/sizeof(iNum[0]);
    FindTheMaxSum(iNum, iCount, ibegin, iend, iResult);
	cout << ibegin <<" "<< iend <<" "<< iResult <<endl;
	return 1;
}

3、最容易想到的就是穷举搜索。在n个序列中求出每k个连续序列的值,进行比较。

示例代码

#include <iostream>

using namespace std;

void FindTheMaxKSum(int iNumPar[], const int iSize, int iK, int &ibegin, int &iend, int &iMaxSum)
{
//iK指出求最大各子序列的长度
	int iTemMaxKsum = 0;
	for (int i = 0; i < iK; ++i)
	{
		iTemMaxKsum += iNumPar[i];
	}
	iMaxSum = iTemMaxKsum;
	
	int iStart = ibegin = 0, iOver = iend = iK - 1;
	for (int i = 1; (i < iSize) && ((iSize - i) >= iK); ++i)
	{
		iTemMaxKsum = 0;
		for (int j = i; ((j - i) < iK) && (j < iSize); ++j)
		{
			iTemMaxKsum += iNumPar[j];
		}

		if (iTemMaxKsum > iMaxSum)
		{
			iMaxSum = iTemMaxKsum;
			ibegin = i;
			iend = i + iK - 1;
		}
	}
}

int main()
{
    int ibegin = 0, iend = 0, iResult = 0, iCount = 0;
	int iNum[] = {-1, -2, 4, 5, 6, 1, 2, 3, 4, -4, -20, 40, -3};
	iCount = sizeof(iNum)/sizeof(iNum[0]);
    FindTheMaxKSum(iNum, iCount, 3, ibegin, iend, iResult);
	cout << ibegin <<" "<< iend <<" "<< iResult <<endl;
	return 1;
}

由上可见,复杂度为O(iK + n*k)

那么有没有更好的方法呢?优化的方法就是把循环体内的相加循环去掉。

示例代码

#include <iostream>

using namespace std;

void FindTheMaxKSum(int iNumPar[], const int iSize, int iK, int &ibegin, int &iend, int &iMaxSum)
{
//iK指出求最大各子序列的长度

	int *pTempSum = new int[iSize];
	pTempSum[0] = iNumPar[0];
	for (int i = 1; i < iSize; i++)
	{
		pTempSum[i] = pTempSum[i - 1] + iNumPar[i]; 
	}
	
	int iStart = ibegin = 0;
	ibegin = 0;
	iend = iK - 1;
	iMaxSum = pTempSum[iend];

	for (int i = 1, j = iK; j < iSize; ++i, ++j)
	{
		if ((pTempSum[j] - pTempSum[i - 1]) > iMaxSum)
		{
			iMaxSum = pTempSum[j] - pTempSum[i - 1];
			ibegin = i;
			iend = j;
		}
	}
delete pTempSum[];
}

int main()
{
    int ibegin = 0, iend = 0, iResult = 0, iCount = 0;
	int iNum[] = {-1, -2, 4, 5, 6, 1, 2, 3, 4, -4, -20, 40, -3};
	iCount = sizeof(iNum)/sizeof(iNum[0]);
    FindTheMaxKSum(iNum, iCount, 3, ibegin, iend, iResult);
	cout << ibegin <<" "<< iend <<" "<< iResult <<endl;
	return 1;
}

    由上可见,程序复杂度为O(n)n为问题规模。

参考

[1]更多的数学说明:

http://www.cnblogs.com/Jason_Yao/archive/2009/09/27/1574713.html

[2]CSDN论坛中的讨论

http://topic.csdn.net/u/20110402/12/795e568e-b590-4fb0-8a4d-dba8b408441f.html?1021658511

posted @ 2011-04-02 14:18  浪里飞  阅读(858)  评论(1编辑  收藏  举报