最大字段和各种不同算法实现(参考编程珠玑)

求最大字段和的算法很好的讲解了算法设计技术。根据《编程珠玑》上的描述,简单实现各种不同的算法。如下:

1、最简单的方法:对所有满足0≤i≤j<n的(i,j)整数进行迭代。对每个整数对,都计算x[i..j]的总和:

简单方法
int maxSum_easy(int n, int* a, int& besti, int& bestj) //最简单的方法,复杂度为O(n^3)
{
    int maxSoFar = 0, i = 0, j = 0, k = 0, sum = 0;
    for (i = 0; i < n; ++i)
        for ( j = i; j < n; ++j)
        {
            sum = 0;
            for (k = i; k<=j; ++k)
                sum += *(a+k);
            if (sum > maxSoFar)
            {
                maxSoFar = sum;
                besti = i;
                bestj = j;
            }
            
        }
    return maxSoFar;
}

2、改进简单的方法,将复杂度变为O(n2),注意子和求解过程,分别有两种改进方法:

  方法一,如下: 

改进一
int maxSum_O2na(int n, int *a, int& besti, int& bestj)//改进上一算法,时间复杂度变为O(n^2)
{
    int maxSoFar = 0, i = 0, j = 0, k = 0, sum = 0;
    for (i = 0; i < n; ++i)
    {
        sum = 0;
        for (j = i; j < n; ++j)
        {
            sum += *(a+j);
            if (sum > maxSoFar)
            {
                maxSoFar = sum;
                besti = i;
                bestj = j;
            }
        }
    }
    return maxSoFar;
}

  方法二,如下:

改进二
int maxSum_O2nb(int n, int *a, int& besti, int& bestj) //增加一累加数组,时间复杂度变为O(n^2)
{
    int maxSoFar = 0, i = 0, j = 0,  sum = 0;
    int * acc = new int[n+1]; //创建一个额外的累加器
    *(acc) = 0;
    for (i = 1; i <= n; ++i)
        *(acc+i) = * (acc+i-1) + *(a+i-1);
    for (i = 0; i < n; ++i)
        for (j = i; j < n; ++j)
        {
            sum = *(acc+j+1) - *(acc+i); // sum is sum of a[i..j]
            if (sum > maxSoFar)
            {
                maxSoFar = sum;
                besti = i;
                bestj = j;
            }
        }
    delete acc;
    return maxSoFar;
}

3、同时,还可以利用分治法对其进行求解,复杂度为O(nlogn)代码如下:

分治法求解
int maxSum_ConDiv(int *a, int left, int right)//分治法,复杂度为O(nlogn),调用形式为maxSum_ConDiv(a,0,n-1)
{
    int maxSoFar = 0, sum = 0, i = 0, m = (left+right)/2, lmax =0, rmax = 0, lsub = 0, rsub =0;
    if (left > right) //zero elements
        return 0;
    if (left == right) //one element
        return left > 0 ? left : 0;
    for (i = m; i >= left; --i)
    {
        sum += *(a+i);
        if (sum > lmax)
            lmax = sum;
    }
    sum = 0;
    for (i = m+1; i <= right; ++i)
    {
        sum += *(a+i);
        if (sum > rmax)
            rmax = sum;
    }
    
    //find max value among the 3 values and return it
    lsub = maxSum_ConDiv(a,left,m);
    rsub = maxSum_ConDiv(a,m+1,right);
    maxSoFar = lmax + rmax;
    if (lsub > maxSoFar)
        maxSoFar = lsub;
    if (rsub > maxSoFar)
        maxSoFar = rsub;
    return maxSoFar;
}

4、另外一种方法,是效率最高的,复杂度为O(n),利用了动态规划的思想,代码如下:

动态规划求解
int maxSum_sm(int* a, int n) //扫描算法,时间复杂度为O(n)
{
    int maxSoFar = 0, maxendinghere = 0, i =0, temp =0;
    for (; i < n; ++i)
    {
        maxendinghere = maxendinghere+a[i];
        maxendinghere = maxendinghere > 0 ? maxendinghere : 0;
        
        if (maxendinghere > maxSoFar)
            maxSoFar = maxendinghere;
    }
    return maxSoFar;
}

测试实验如下所示:

int main()
{
    int a[] = {31, -41, 59, 26, -53, 58, 97, -93, -23, 84},
        n, besti = 0, bestj = 0, maxSum = 0;
    n = sizeof(a)/sizeof(a[0]);
    cout << "a的最大子和为:" <<  maxSum_sm(a,n) << endl;
    //cout << ";是 " << besti << "->" << bestj << "的和" << endl;
    return 0;
}

 

posted @ 2013-04-15 00:27  busyfruit  阅读(475)  评论(0编辑  收藏  举报