最大子序列和问题(mooc笔记)

对于这个问题我们给出三种算法:

算法1:T(N) = O(N^2)
一种笨办法,两个for循环,起点从下标0开始,每遍历一次就加1再遍历,一直加到N,这样就得到了最后的结果,思路不难但是不算好。

代码如下:

int MaxSubSequenceSum(int A[],int N){
    int ThisSum,MaxSum;
    
    MaxSum = 0;
    for(int i = 0; i < N; i++){
        ThisSum = 0;
        for(int j = i; j < N; j++){
            ThisSum += A[j];
            if(ThisSum > MaxSum) 
            	MaxSum = ThisSum;
            }
        }
    return MaxSum;
}

算法2:T(N) = O(N)
该算法的优点是它只对数据进行一次扫描,一旦完成对A[ i ]的读入和处理,就不再需要记忆它了,具有这种特性的算法叫做联机算法(on-line algorithm)

代码如下:

int submax2(int A[],int N){
    int ThisSum,MaxSum;

    ThisSum = MaxSum = 0;
    for(int i = 0; i < N; i++){
        ThisSum += A[i];	//向右累加

        if(ThisSum > MaxSum) 
        	MaxSum = ThisSum;	//发现更大的则更新当前结果
        else if(ThisSum < 0)	//如果当前子列和为负,则不可能使后面的部分增大,抛弃掉 
        	ThisSum = 0;
        }
    return MaxSum;
}

算法3:T(N) = O(N logN)
分治法:将问题分成两个大致相等的子问题,然后递归地对它们求解。
对于这个问题,最大子序列和可能在三处出现,将序列分成两半部分,则最大子序列可能全在左半部分,可能全在右半部分,又或者它横跨这两部分。有了这个思路,我们就可以用递归来求解,虽然相对复杂,但是体现出了递归的威力。

代码如下:

int Max3(int a,int b,int c){
    return a>b?(a>c?a:c):(b>c?b:c);	//返回三个整数中的最大值
}

int MaxSubSum(int A[],int Left,int Right){
    int MaxLeftSum,MaxRightSum;	//左半部分和右半部分的最大子序列和
    int MaxLeftBorderSum,MaxRightBorderSum;	//从中点向左右两边扫描的最大子序列和
    int LeftBorderSum,RightBorderSum;
    int Center,i;

    if(Left == Right){	//递归的终止条件,子列只有一个数字
        if(A[Left] > 0)
            return A[Left];
        else
            return 0;
        }

    Center = (Left + Right)/2;	//找到中分点,递归求得两边子列的最大和
    MaxLeftSum = MaxSubSum(A,Left,Center);
    MaxRightSum = MaxSubSum(A,Center+1,Right);
	
	//求跨分界线的最大子列和(这里和联机算法有些相似)
    MaxLeftBorderSum = LeftBorderSum = 0;
    for(i = Center; i >= Left; i--){
        LeftBorderSum += A[i];
        if(LeftBorderSum > MaxLeftBorderSum)
            MaxLeftBorderSum = LeftBorderSum;
        }

    MaxRightBorderSum = RightBorderSum = 0;
    for(i = Center+1; i <= Right; i++){
        RightBorderSum += A[i];
        if(RightBorderSum > MaxRightBorderSum)
            MaxRightBorderSum = RightBorderSum;
        }
        
	//MaxLeftBorderSum+MaxRightBorderSum就是跨分界线的最大子列和,然后三者比较
    return Max3(MaxLeftSum,MaxRightSum,MaxLeftBorderSum+MaxRightBorderSum);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值