四種方法解決最大連續子序列和問題


什么是最大連續子序列和問題?

問題描述:給定一個序列(整數或浮點數),求出其中連續的子序列和最大的那一個。

例:序列{-10 1 2 3 4 -5 -23 3 7 -21},其最大的連續子序列為{1 2 3 4}或{3 7},最大和為10.

方法一:暴力求解

最最普通的方法,效率十分低,一般不會用到,這里簡單介紹。直接兩個for循環枚舉子序列的首尾,再來一個for循環計算首尾之間的序列和,計算所有的序列和,找到最大值。

時間復雜度:O(n^3)

效率賊低,千萬不要用!(所就不貼代碼了)

 

方法二:預處理暴力求解

第一種方法為什么這么慢,原因之一是每次都要計算首尾之間的序列和。基於這個考慮,我們可以對數據進行預先處理:讀入數據時使用一個數組SUM[i]來記錄前i項數據之和。用這種方法,只需要兩個for循環枚舉子序列的首尾,利用SUM數組計算子序列和,找到最大值。

時間復雜度:O(n^2)

還是很糟糕,建議不要用。(所以也不貼代碼qwq)

 

方法三:分治法求解

把序列分成左右兩部分,一般對半分,數量不等也沒關系。最大子序列和的位置存在三種情況:1、完全在左半部分;2、完全在右半部分;3、跨越左右兩部分。分別求出左半部分的最大子序列和、右半部分的最大子序列和、以及跨越左右兩部分的最大子序列和,三者中的最大者就是要求的。

如何求三部分的最大子序列和呢?

左半部分的最大子序列和,可把左半部分作為新的輸入序列通過該算法遞歸求出。右半部分的最大子序列和同理。

接下來就是求解跨越左右兩部分的最大子序列和,也就是求出包含左半部分中最右邊元素的子序列的最大和,和包含右半部分中最左邊元素的子序列的最大和,將兩者相加即為跨越左右兩個部分的最大子序列和。具體見如下代碼:

//分治算法 
int a[999999];

int MAxSubSum(int left,int right)
{
    int sum=0;
    if(left==right)//基本情況:只有一個元素 
        sum=a[left]>0?a[left]:0;
    else
    {
        int center=(left+right)/2;
        int leftsum=MaxSubSum(left,center);//左半部分 
        int rightsum=MAxSubSum(center+1,right);//右半部分 
        
        //求包含左半部分最右元素的最大和 
        int s1=0;
        int lefts=0;
        for(int i=center;i>=left;i--)
        {
            lefts+=a[i];
            if(lefts>s1) s1=lefts;
        }
        
        //求包含右半部分最左元素的最大和 
        int s2=0;
        int rights=0;
        for(int i=center+;i<=right;i++)
        {
            rights+=a[i];
            if(rights>s2) s2=rights;
        }
        
        //取三者最大值 
        sum=s1+s2;
        if(sum<leftsum) sum=leftsum;
        if(sum<rightsum) sum=rightsum;
    }
    return sum;
}

時間復雜度:O(nlgn)

運用遞歸思想,一層一層分解,最終解決問題。效率還好,有助於理解分治與遞歸,可以嘗試使用。

 

方法四:動態規划

這是最常見的方法了,簡單有效,好理解。

狀態轉移方程:sum[i] = max{sum[i-1]+a[i],a[i]}. (sum[i]記錄以a[i]為子序列末端的最大序子列連續和)

其實完全可以不用開數組,累計sum直到sum + a < a,把sum賦值為a,更新最大值就行了。

//動態規划算法
int MaxSum(int n)
{
    int sum=0,b=0;
    for(int i=0;i<n;i++)
    {
        if(b>0) b+=a[i];
        else b=a[i];
        if(b>sum) sum=b;
    }
    return sum;
}

時間復雜度:O(n)

這是好用的求最大子序列的方法了,牆裂推薦!

 

相關題目練習:

hdu 1003:http://acm.hdu.edu.cn/showproblem.php?pid=1003

hdu 1231:http://acm.hdu.edu.cn/showproblem.php?pid=1231

 

作者: AlvinZH

出處: http://www.cnblogs.com/AlvinZH/

本人Github:https://github.com/Pacsiy/JobDu

本文版權歸作者AlvinZH和博客園所有,歡迎轉載和商用,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM