分而治之的递归思想(最大子列和的nlogn解法)

- 递归问题常见解题思路

  1. 明确递归的目的
  2. 寻找递归的结束条件
  3. 寻找函数的等价关系式

- 最大子列和问题
问题描述:给定n个整数的序列{a1,a2,------an},寻找函数f(i,j)=max{0,∑(i,j)ak}

算法一:部分穷举法
复杂度:o(n^2) 不推荐

int MaxSubseqSum(int list[], int n){
	int i, j;  
	int Thissum,Maxsum=0;
	for(i=0;i<n;i++){
		Thissum=0;
		for(j=i;j<n;j++){
			Thissum+=list[j];
			Maxsum=Thissum>Maxum?Thissum:Maxsum;
		}
	}
	return Maxsum;
}

算法二:分而治之
第一步:将序列从中间分成两个子序列
第二步:递归球的两子列的最大与最小值
第三步:从中间开始向两边扫描,寻找最大值。
第四步:s=max{左,中,右}

int Max3(int A, int B, int C){
	return A>B?A>C?A:C:B>C?B:C;				//返回三个中最大值,也可以用(A>B?A:B)>C?(A>B?A:B):C
}
int DivideAndConquer(int list[], int left, int right){
	int MaxLeftBorderSum=0,MaxRightBorderSum=0; //存放中中间往两边的两个最大值
	int MaxLeftSum,MaxRightSum;				//存放左,右两人子列的最大值
	int center,i;
	int LeftBoederSum=o,RightBorderSum=0;
	
	//结束条件 (判断是否左右相等)
	if(left==right){
		if(list[left]>0){
			return list[left];
		}
		else
			return 0;
	}
	center=(left + right)/2;
	MaxLeftSum=DivideAndConquer(list[], left,center);
	MaxRightSum=DivideAndConquer(list[],center,right);
	//取从中间开始的往左边子列最大值
	for(i=center; i>=left; i--){
		LeftBorderSum + = list[i];
		MaxLeftBorderSum = LeftBorderSum > MaxLeftBorderSum ? LeftBorderSum : MaxLeftBorderSum;
	}
	//取从中间开始的往右边的子列最大值
	for(i=center; i<=right; i++){
		RightBorderSum + = list[i];
		MaxRightBorderSum = RightBorderSum > MaxRightBorderSum ? RightBorderSum : MaxRightBorderSum;
	}
}
	return Max3(MaxLeftSum , MaxRightSum , MaxLeftBorderSum + MaxRightBorderSum);

分而治之的算法时间复杂度为nlogn

算法三:在线处理
基于:如果整数序列{a1,a2,an}最大子列是{ai,aj}
,那么对于任意的i < = l < = j, 恒有ai+,,,,+al>0

int MaxSubseqSum3(int list[], int n){
	int i;
	int ThisSum,MaxSum;
	ThisSum=MaxSum=0;
	
	for(i=0;i<n;i++){
		ThisSum+=list[i];
		if(ThisSum>MaxSum){
			MaxSum=ThisSum;
		}
		else if(ThisSum<0){
			ThisSum=0;
		}
	}
	return MaxSum;
}

提高效率的关键在于:让计算机记住一些关键结果,避免重复运算

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