求數組中最長遞增子序列的長度


求數組中最長遞增子序列的長度

什么是最長遞增子序列呢?
問題描述如下:
   設L=<a1,a2,…,an>是n個不同的實數的序列,L的遞增子序列是這樣一個子序列Lin=<aK1,ak2,…,akm>,其中k1<k2<…<km且aK1<ak2<…<akm。求最大的m值。

如:在序列1,-1,2,-3,4,-5,6,-7中,其最長的遞增子序列為1,2,4,6。其長度為4。
對於這個問題有以下幾種解決思路:
   1、把a1,a2,...,an排序,假設得到a'1,a'2,...,a'n,然后求a的a'的最長公共子串,這樣總的時間復雜度為o(nlg(n))+o(n^2)=o(n^2);
   2、動態規划的思路:
    另設一輔助數組b,定義b[n]表示以a[n]結尾的最長遞增子序列的長度,則狀態轉移方程如下:b[k]=max(max(b[j]|a[j]<a[k],j<k)+1,1);
    這個狀態轉移方程解釋如下:在a[k]前面找到滿足a[j]<a[k]的最大b[j],然后把a[k]接在它的后面,可得到a[k]的最長遞增子序列的長度,或者a[k]前面沒有比它小的a[j],那么這時a[k]自成一序列,長度為1.最后整個數列的最長遞增子序列即為max(b[k]   | 0<=k<=n-1);
    實現代碼如下:

 

#include <iostream>
using namespace std;
int main()
{
       int i,j,n,a[100],b[100],max;
       while(cin>>n)
       {
              for(i=0;i<n;i++)
                     cin>>a[i];
              b[0]=1;//初始化,以a[0]結尾的最長遞增子序列長度為1
              for(i=1;i<n;i++)
              {
                     b[i]=1;//b[i]最小值為1
                     for(j=0;j<i;j++)
                            if(a[i]>a[j]&&b[j]+1>b[i])
                                   b[i]=b[j]+1;
              }
              for(max=i=0;i<n;i++)//求出整個數列的最長遞增子序列的長度
                     if(b[i]>max)
                            max=b[i];
              cout<<max<<endl;
       }
       return 0;
}

顯然,這種方法的時間復雜度仍為o(n^2);

 3、對第二種思路的改進:
    第二種思路在狀態轉移時的復雜度為o(n),即在找a[k]前面滿足a[j]<a[k]的最大b[j]時采用的是順序查找的方法,復雜度為o(n).
    設想如果能把順序查找改為折半查找,則狀態轉移時的復雜度為o(lg(n)),這個問題的總的復雜度就可以降到nlg(n).

 


免責聲明!

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



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