0.分治永远大于顺序?关于最大子序列和问题的思考

Posted clclcl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了0.分治永远大于顺序?关于最大子序列和问题的思考相关的知识,希望对你有一定的参考价值。

p17. 2.4.3 最大子序列和的问题的解

 题目:给定整数A1,A2,......,AN,k=i~jAk的最大值(如果所有整数都为负数,则最大子序列和为0)

书中给出了四种不同的算法,时间复杂度依次降低,下面我简单描述一下这四种算法

第一种:穷举法

求出所有子序列和,比较得出最大的

最简单想到的代码,效率十分低下,原因是没有利用数列的连贯性,对数列元素反复检索造成浪费

三层嵌套循环,时间复杂度

T(N)=O(N3)

 

int 
Maxsubsum(const int A[],int N)
{
    int ThisSum,Maxsum,i,j,k;
    
    Maxsum=0;                     
    for(i=0;i<N;i++)              //确定各个子序列的首项
        for(j=i;j<N;j++)            //确定每个序列的元素个数
        {
            ThisSum=0;
            for(k=i;k<=j;k++)              /*开始按照确定的元素个数选出数列并计算子列和,较大者覆盖Maxsum,较小者在ThisSum中被丢弃*/
                ThisSum += A[k];

            if(ThisSum>Maxsum)
                Maxsum=ThisSum;
        }

    return Maxsum;
}

 

第二种:改良后的穷举法

 

顾名思义,这种方法对方法一进行了改良.

当第选定了子序列的首项后,无需对子序列长度进行再次分组,直接顺序列出所有该首项下的子数列即可,减去了一次循环。

实际上换汤不换药

时间复杂度依旧为幂函数级

T(N)=O(N2)

int 
Maxsubsum(const int A[],int N)
{
    int ThisSum,Maxsum,i,j,k;
    
    Maxsum=0;                     
    for(i=0;i<N;i++)//确定各个子序列的首项
    {
        ThisSum=0;
        for(k=i;k<=j;k++)/*开始按照确定的元素个数选出数列并计算子列和,较大者覆盖Maxsum,较小者在ThisSum中被丢弃*/
            {
                ThisSum += A[k];

                if(ThisSum>Maxsum)
                Maxsum=ThisSum;
            }
    }

    return Maxsum;
}

 

第三种:分治法


这是我们今天着重要探讨的第一种算法。

先上代码。

 1 #include "stdio.h"
 2 int
 3 MaxSubSum(const int A[],int left,int right)//left,right分别为数列数组第一个元素和最后一个元素的下标
 4 {
 5     int Maxleftsum,Maxrightsum;
 6     int Maxleftbordersum,Maxrightbordersum;
 7     int leftbordersum,rightbordersum;
 8     int Center,i;
 9 
10     if(left==right)    /*base case*/
11         if(A[left]>0)
12             return A[left];
13         else
14             return 0;
15 
16 
17     Center=(left+right)/2;
18     Maxleftsum=MaxSubSum(A,left,Center);
19     Maxrightsum=MaxSubSum(A,Center+1,right);
20 
21     Maxleftbordersum=0;leftbordersum=0;
22     for(i=Center;i>=left;i--)
23     {
24         leftbordersum +=A[i]
25         if(leftbordersum>Maxleftbordersum)
26             Maxleftbordersum=leftbordersum;
27     }
28 
29     Maxrightbordersum=0;rightbordersum=0;
30     for(i=Center+1;i<=right;i++)
31     {
32         rightbordersum +=A[i]
33         if(rightbordersum>Maxrightbordersum)
34             Maxrightbordersum=rightbordersum;
35     }
36 
37     return Max(Maxleftbordersum,Maxrightbordersum,Maxrightbordersum+Maxleftbordersum)
38 
39 }

 看起来可能有些复杂哈,我第一次看也是半天看不懂,没有这方面的基础。

我们先来看一个简单的问题来理解啥叫分治。



以上是关于0.分治永远大于顺序?关于最大子序列和问题的思考的主要内容,如果未能解决你的问题,请参考以下文章

关于递归排序和快速排序的衍生思考

分治算法解最大子序列和问题

算法设计与分析--求最大子段和问题(蛮力法分治法动态规划法) C++实现

动态规划的设计思想与实例(最大子段和最长公共子序列0-1背包编辑距离)

暴力+分治+贪心+DP:最大子序列和

分治法(求最大子序列和)