最大子序列和的四种算法之讲解


----------------------------------------------------------------------------------------------------------------------------------------------------

最大子序列和的四种算法之讲解_第1张图片

-----------------------------------------------------------------------------------------------------------------------------------------------------



方法一:

  • 暴力求解法,即使用三重循环进行遍历,其时间复杂度为0(N^3)
代码如下:
/*
--------------------------------------------------
function: to calculate the maximum sequence sum of
		  the given sequence; if all are negative,
		  to make the sum equal 0
example:
	input: 6
		   -7 6 -3 4 -2 1
	output: 7

author: sunny
date: 2017.03.05
platform: ubuntu 14.04LTS
complier: gcc 
-------------------------------------------------
 */

#include 


int GetNumCount(void);  //to get the count of the number
void GetSeqNum(int [], int);
void ClearIOBuffer(void);  //to clear the input buffer
int GetMaxSeqSum(int [], int);

int main(void)
{
	int numCount, MaxSeqSum;
	int numArray[numCount];

	numCount = GetNumCount();
	GetSeqNum(numArray, numCount);	
	MaxSeqSum = GetMaxSeqSum(numArray, numCount);
	printf("MaxSeqSum = %d\n", MaxSeqSum);

	return 0;
}

int GetNumCount(void) {
	
	int count;
	printf("Enter the count of number:");
	scanf("%d", &count);
	ClearIOBuffer();

	return count;
}

void ClearIOBuffer(void) {
	
	while(getchar() != '\n')
		continue;
}

void GetSeqNum(int numArray[],int  numCount) {
	
	int i;
	printf("Input the number:");
	for(i = 0; i < numCount; i++)
		scanf("%d", &numArray[i]);
	ClearIOBuffer();
}

int GetMaxSeqSum(int numArray[], int numCount) {

	// to use triple loops
	int i, j, k;
	int thisSum, maxSum;
	thisSum = maxSum = 0;
	for(i = 0; i < numCount; i++) {
		
		for(j = i; j < numCount; j++) {
			
			for(k = i; k <= j; k++) {
			
				thisSum += numArray[k];
				if(thisSum > maxSum)
					maxSum = thisSum;
			}
			thisSum = 0;  //to make a new accumulation
		}
	}
	
	return maxSum;
}



运行结果如下:



方法二:


  • 对方法一(暴力求解法)进行改进,去掉冗余的第三重循环,改用二重循环即可做到,其时间复杂度为0(N^2)
代码如下:
将方法一中的函数用下面的函数进行替换
int GetMaxSeqSum(int numArray[], int numCount) {

	// to use triple loops
	int i, j;
	int thisSum, maxSum;
	thisSum = maxSum = 0;
	for(i = 0; i < numCount; i++) {
		
		thisSum = 0;  //to make a new accumulation
		for(j = i; j < numCount; j++) {
				
			thisSum += numArray[j];
			if(thisSum > maxSum)
				maxSum = thisSum;
		}
	}
	
	return maxSum;
}


方法三:

  • 尽管方法2用二重循环即可求解问题,但其时间复杂度仍为0(N^2),对于时间复杂度为0(N^2)的算法,我们
必须尽可能想办法去减小时间复杂度,因为当数据量较大时,其运算需要的时间仍然很长。
  • 我们想到分治的方法,即分而治之。
分:即将问题分为两个大致相等的子问题,然后采用递归求解;
治:综合考虑两个子问题的解,最后得到整个问题的解。
  • 此问题中,采用分治的思想,能将时间复杂度减小为0(n*lgn),稍后我们将给出证明
先给出代码:
int GetMaxSeqSum(int [], int);
int MaxDivAndConquerSum(int [], int, int);
int GetMaxInThree(int, int, int);

int MaxDivAndConquerSum(int numArray[], int leftIndex, int rightIndex) {
	
	//divide and conquer method
	int maxLeftSeqSum, maxRightSeqSum;
	int maxLeftBorderSeqSum, maxRightBorderSeqSum;
	int thisSum;
	int centerIndex, i;

	if(leftIndex == rightIndex) {
	
		if(numArray[leftIndex] > 0)
			return numArray[leftIndex];
		else
			return 0;
	}

	centerIndex = (leftIndex + rightIndex) / 2;
	maxLeftSeqSum = MaxDivAndConquerSum(numArray, leftIndex, centerIndex);
	maxRightSeqSum = MaxDivAndConquerSum(numArray, centerIndex + 1, rightIndex);

	maxLeftBorderSeqSum = 0;
	thisSum = 0;
	for(i = centerIndex; i >= leftIndex; i--) {
	/*
   	----------------------------------------------------------	   
	don't write like this: for(i = leftIndex; i <= centerIndex; i++)
		this is wrong, because it can't ensure the last element
	of the first half part is included
	----------------------------------------------------------
	 */	
		thisSum += numArray[i];
		if(thisSum > maxLeftBorderSeqSum)
			maxLeftBorderSeqSum = thisSum;
	}

	maxRightBorderSeqSum = 0;
	thisSum = 0;
	for(i = centerIndex + 1; i <= rightIndex; i++) {
	
		thisSum += numArray[i];
		if(thisSum > maxRightBorderSeqSum)
			maxRightBorderSeqSum = thisSum;
	}
	
	return GetMaxInThree(maxLeftSeqSum, maxRightSeqSum, 
		maxLeftBorderSeqSum + maxRightBorderSeqSum); 
}

int GetMaxInThree(int num1, int num2, int num3) {

	return num1>num2?(num1>num3?num1:num3):(num2>num3?num2:num3);
}

int GetMaxSeqSum(int numArray[], int numCount) {
	
	return MaxDivAndConquerSum(numArray, 0, numCount - 1);
}

以下我们计算其时间复杂度:

最大子序列和的四种算法之讲解_第2张图片


方法四:


下面我们利用联机算法或者叫做在线算法来计算最大子序列和的问题。
  • 这个算法有个特点,即:数据只需一次扫描,便可给出结果,无需在主机内存进行存储;并且在任何时
刻,此算法都能根据输入给出正确结果。
  • 此算法非常高效,时间复杂度仅为0(N)

代码如下:

int GetMaxSeqSum(int numArray[], int numCount) {

	int maxSeqSum, thisSum;
	int i;
	
	maxSeqSum = thisSum = 0;
	for(i = 0; i < numCount; i++) {
	
		thisSum += numArray[i];
		if(thisSum > maxSeqSum)
			maxSeqSum = thisSum;
		else if(thisSum < 0)
			/*the following statement is the key!!!
		    if thisSum is negative, it can't make
		    itself bigger. So it returns to zero.	
			*/	
			thisSum = 0;
	}

	return maxSeqSum;
}


总结:

    通过对比上述四种算法,相信你一定能够深刻理解算法的重要性!一起加油吧!^-^































你可能感兴趣的:(数据结构与算法)