最大子列和

//计算最大子列和,T(n)=O(n^2)
#include <stdio.h>
#include <stdlib.h>
//一旦由i确定左端,thisSum就从左端往右加,加一个值更新一次thisSum
//当第二个数作为左端时,thisSum要归0,因为这代表着第二种序列
int main()
{
    int a[n];
    int i,j;
    int maxSum=0,thisSum;
    for(i=0;i<n;i++)//i为左端
    {
        thisSum=0;
        for(j=i;j<n;j++)//j为右端
        {
            thisSum+=a[j];
            if(thisSum > maSum)
                maxSum = thisSum;
        }
    }
    return 0;
}
View Code

时间复杂度为O(N^2)

第二种算法:分治法,复杂度为O(N*logN)

分治的思想在于将数组分为左半部和右半部,且左右部相互独立,分别去求左半部和右半部的最大子列和

再求从中轴线开始,向左扫描,得MaxLeftBorderSum和MaxRightBorderSum,将他们加起来得到贯穿中轴线的子列和

最大子列和逃不出三个部分,所以max3(MaxLeftSum,MaxLeftBorderSum+MaxRightBorderSum)就是最大子列和

//分治法计算最大子列和,时间复杂度为T(N*logN)
#include <stdio.h>
#include <stdlib.h>
int A[N];
int MaxSubSum(int A[],int left,int right)
{
    int LeftSubSum,RightSubSum,LeftBorderSum=0,RightBorderSum=0;
    int center,MaxLeftBorderSum=0,MaxRightBordersum=0;
    if(left == right)
    {
        if(A[left] > 0)
            return A[left];
        else
            return 0;
    }
    center=(right+left)/2;
    LeftSubSum=MaxSubSum(A,left,center);
    RightSubSum=MaxSubSum(A,center+1,right);
    for(i=center; i >= left; i--)
    {
        LeftBorderSum+=A[i];
        if(LeftBorderSum > MaxleftBorderSum)
            MaxLeftBorderSum=LeftBorderSum;
    }
    for(i=center+1; i<=right; i++)
    {
        RightborderSum+=A[i];
        if(RightBorderSum > MaxRightBorderSum)
            MaxRightBorderSum= RightBorderSum;
    }
    return max3(LeftSubSum,RightSubSum,MaxLeftBorderSum+MaxrightBorderSum);
}
int main()
{
    return MaxSubSum(A,0,N-1);
}
View Code

 求左半部的最大子列和,就和求一整块的最大子列和一样,再分成左半部和右半部

每次递归,LeftBordersum/RightBordersum以及MaxBorderSum都从0开始

疑惑的是如果都是负数,最大子列和不就为0吗?

第三种算法:online algorithm(在线算法)

每次加一个到ThisSum,如果某次小于0,ThisSum归0,因为让这个负的ThisSum再往后加,只可能让当前加的这个数变小

所以,直接抛弃前面,从为正的开始

这个算法的正确性让我难以证明

//在线算法计算最大子列和,时间复杂度为T(N)
#include <stdio.h>
#include <stdlib.h>

int SubSum(int A[])
{
    int ThisSum=0,Maxsum=0;
    for(i=0;i<n; i++)
    {
        ThisSum+=A[i];
        if(ThisSum > MaxSum)
            MaxSum=ThisSum;
        if(ThisSum < 0)
            ThisSum=0;
    }
}

int main()
{
    return SubSum();
}
View Code

第二种算法的时间复杂度分析:

T(n)=2T(n/2)+O(n)

把O(n)换成n(目前的知识不知道为什么,结论是不影响)

第一次:T(n)=2T(n/2)+n

让T(n/2)递推:T(n/2)=2T(n/2^2)+n/2

第二次:T(n)=2^2T(n/2^2)+2n

....

......

第k次:T(n)=2^k*T(n/2^k)+k*n

n/2^k最后会接近1,T(n/2^k)->T(1)=1

且n=2^k -> k==log2 n

-->T(n)=n+n*log n

《算法及数据分析(c)》中默认了n为偶数,我的理解是这样才能使n*logn>n,否则就不能说复杂度是O(n*logn)(因为复杂度总是选取较大的项)

且就算为奇数,分析要复杂些,解雇还是O(n*logn)...(这个地方的分析我先放放)

原文地址:https://www.cnblogs.com/gabygoole/p/4597581.html