1. 程式人生 > >歸納法求解最大連續子序列

歸納法求解最大連續子序列

問題

求最大連續子序列的問題描述如下:

給定一個實數序列 x1, x2, ... , xn(不必是正數),尋找一個(連續的)子序列 xi, xi+1, ... , xj,使得其數值之和在所有連續子序列數值之和中是最大的。

這個問題就是最大子序列問題,所求的的這個序列就叫做——最大子序列。下面通過數學歸納法來分析和解決這個問題,解決這個問題的最好目標是: 一個演算法,能夠只掃描此序列一次就得到最大子序列

歸納分析

根據上面的問題可以直接得到一般的歸納假設:

歸納假設: 已知如何找到規模小於 n 的序列的最大子序列。

下面假定一些變數:

  • 給定序列 S(n)=(x1, x2, ... , xn
    ).
  • 序列 S(n) 的子序列為 S'(n) .
  • 序列 S(n) 的最大子序列為 S'M(n)=(xi, xi+1, ... , xj).
  • 序列 S(n) 的最大字尾子序列為 S'E(n)=(xk, xk+1, ... , xn).

現在開始用數學歸納法來證明:

  1. 當 n = 1 時, S(1)=x1,如果 x1<0,則 *S'M(1)=NULL;否則 *S'M(1)=x1 .
  2. 當 n = n-1 時,S(n-1)=(x1, x2, ... , xn-1),假設 S'M(n-1)=(xi, xi+1, ... , xj).
  3. 當 n = n 時,S(n)=(x1, x2, ... , xn)=( S(n-1)

    , xn),然後由 S'M(n-1) 推匯出 S'M(n),共有下面3種情況:

    1. S'M(n-1)=(xi, xi+1, ... , xj) = NULL,如果 xn<0,則 *S'M(n)=NULL;否則 *S'M(n)=xn .
    2. S'M(n-1)=(xi, xi+1, ... , xj) && j = n-1,此時 S'M(n-1) = S'E(n-1),如果 xn > 0,S'M(n)= S'M(n-1) + xn = (xi, xi+1, ... , xj) + xn,否則 S'M(n)= S'M(n-1)=(xi, xi+1, ... , xj) .
    3. S'M(n-1)
      =(xi, xi+1, ... , xj) && j < n-1,此時 S'M(n-1) > S'E(n-1),則可得到 S'M(n)S'M(n-1) 或者 S'M(n)S'E(n-1) + xn .
  4. 即上述可得證:能夠求出 S(n)=(x1, x2, ... , xn) 的最大連續子序列,不過上述的證明過程中用了增強歸納假設,這個也是這個證明的關鍵:

    更強的歸納假設: 已知如何找到規模小於 n 的序列的最大子序列,以及作為字尾的最大子序列。

我們知道了 S'M(n) 和 S'E(n) 這兩個序列,演算法也就明確了。我們把 xn 加入到最大字尾子序列中,如果它的和大於原來的最大子序列,則得到一個新的最大子序列(同樣也是一個字尾),否則,保留以前的最大子序列。但求解過程還沒有結束,我們還需要尋找新的最大字尾子序列,因為不能只是簡單的把 xn 加到以前的最大字尾中,有可能以 xn 結束的最大字尾的和是負數,在這種情況下,我們就需要把NULL(空集)作為最大字尾(以及把隨後的 xn+1 也考慮進去)。

具體演算法實現

根據上面的分析過程,下面貼上具體的C++程式碼:

int Maximum_Consecutive_Subsequence(int *x, int n)                                 
{                                                                                  
    int global_Max = 0;   // 最大子序列的和                                        
    int suffix_Max = 0;   // 最大字尾子序列的和,每次迭代都會更新                  
    int i = 0;                                                                     
    for (i = 0; i < n; i++)                                                        
    {                                                                              
        if (x[i] + suffix_Max > global_Max)                                                                  
        {                                                                          
            suffix_Max = suffix_Max + x[i];                                        
            global_Max = suffix_Max;                                               
        }                                                                          
        else if (x[i] + suffix_Max > 0)                                            
        {                                                                          
            suffix_Max = suffix_Max + x[i];                                        
        }                                                                          
        else                                                                       
        {                                                                          
            suffix_Max = 0;                                                        
        }                                                                          
    }                                                                              
    return global_Max;                                                             
}

更詳細的程式碼可以戳這裡

2014.09.07