N種方法妙講LIS算法

LIS算法經典彙總算法

假設存在一個序列d[1..9] = 2 1 5 3 6 4 8 9 7,能夠看出來它的LIS長度爲5。
下面一步一步試着找出它。
咱們定義一個序列B,而後令 i = 1 to 9 逐個考察這個序列。
此外,咱們用一個變量Len來記錄如今最長算到多少了

首先,把d[1]有序地放到B裏,令B[1] = 2,就是說當只有1一個數字2的時候,長度爲1的LIS的最小末尾是2。這時Len=1

而後,把d[2]有序地放到B裏,令B[1] = 1,就是說長度爲1的LIS的最小末尾是1,d[1]=2已經沒用了,很容易理解吧。這時Len=1

接着,d[3] = 5,d[3]>B[1],因此令B[1+1]=B[2]=d[3]=5,就是說長度爲2的LIS的最小末尾是5,很容易理解吧。這時候B[1..2] = 1, 5,Len=2

再來,d[4] = 3,它正好加在1,5之間,放在1的位置顯然不合適,由於1小於3,長度爲1的LIS最小末尾應該是1,這樣很容易推知,長度爲2的LIS最小末尾是3,因而能夠把5淘汰掉,這時候B[1..2] = 1, 3,Len = 2

繼續,d[5] = 6,它在3後面,由於B[2] = 3, 而6在3後面,因而很容易能夠推知B[3] = 6, 這時B[1..3] = 1, 3, 6,仍是很容易理解吧? Len = 3 了噢。

第6個, d[6] = 4,你看它在3和6之間,因而咱們就能夠把6替換掉,獲得B[3] = 4。B[1..3] = 1, 3, 4, Len繼續等於3

第7個, d[7] = 8,它很大,比4大,嗯。因而B[4] = 8。Len變成4了

第8個, d[8] = 9,獲得B[5] = 9,嗯。Len繼續增大,到5了。

最後一個, d[9] = 7,它在B[3] = 4和B[4] = 8之間,因此咱們知道,最新的B[4] =7,B[1..5] = 1, 3, 4, 7, 9,Len = 5。

因而咱們知道了LIS的長度爲5。

!!!!! 注意。這個1,3,4,7,9不是LIS,它只是存儲的對應長度LIS的最小末尾。有了這個末尾,咱們就能夠一個一個地插入數據。雖然最後一個d[9] = 7更新進去對於這組數據沒有什麼意義,可是若是後面再出現兩個數字 8 和 9,那麼就能夠把8更新到d[5], 9更新到d[6],得出LIS的長度爲6。

而後應該發現一件事情了:在B中插入數據是有序的,並且是進行替換而不須要挪動——也就是說,咱們可使用二分查找,將每個數字的插入時間優化到O(logN)~~~~~因而算法的時間複雜度就下降到了O(NlogN)~!
藉助例題 數組

hdu 1257 最少攔截系統

Problem Description
某國爲了防護敵國的導彈襲擊,發展出一種導彈攔截系統.可是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈可以到達任意的高度,可是之後每一發炮彈都不能超過前一發的高度.某天,雷達捕捉到敵國的導彈來襲.因爲該系統還在試用階段,因此只有一套系統,所以有可能不能攔截全部的導彈.
怎麼辦呢?多搞幾套系統唄!你說說倒蠻容易,成本呢?成本是個大問題啊.因此俺就到這裏來求救了,請幫助計算一下最少須要多少套攔截系統.
 

 

Input
輸入若干組數據.每組數據包括:導彈總個數(正整數),導彈依此飛來的高度(雷達給出的高度數據是不大於30000的正整數,用空格分隔)
 

 

Output
對應每組數據輸出攔截全部導彈最少要配備多少套這種導彈攔截系統.
 

 

Sample Input
8 389 207 155 300 299 170 158 65
 

 

Sample Output
2
經典LIS算法,與求最大上升子序列類似:
以數組 h[] 記錄攔截系統當前的攔截高度,先初始化爲最大值 INF = 30000+10,
表示每個新攔截系統都能攔截全部的導彈,而後遇到一個導彈就往前找看是否有已經使用了的系統能攔截,若是有,直接用;不然從新弄一個系統。最後再看用了幾個系統就行了。
 
第一個導彈 389 < h[1] ( h[1] = INF)被第一個系統攔截 h[1] = 389
第二個導彈 207 < h[1] 被第一個系統攔截 h[1] = 207
第三個導彈 155 < h[1] h[1] = 155
第四個導彈 300 > h[1] , 300 < h[2] ( h[2] = INF ) 因此新開發一個系統攔截第四個導彈, h[2] = 300
第五個導彈 299 > h[1] , 299 < h[2] 被第二個系統攔截 h[2] = 299
第六個導彈 170 > h[1] , 170 < h[2] h[2] = 170
第七個導彈 158 > h[1] , 158 < h[2] h[2] = 158
第八個導彈 65 < h[1] 被第一個系統攔截 h[1] = 65
 
因此最後使用了兩個系統就攔截了全部的導彈【遍歷 h[]數組從 1到 n 看有幾個 != INF 就說明使用了】
 
導彈高度:389 207 155 300 299 170 158 65
使用的攔截系統: 1 1 1 2 2 2 2 1
 求最長上升子序列:

      給定排好序的一堆數列中,求其的LIS長度。它的LIS長度就是它非上升子序列的個數。優化

此題能夠用N種方法講解,下面一一爲你們講解:spa

方法一:DP解法:code

 1 #include<stdio.h>
 2 #define MAX(x,y) x>y?x:y
 3 int dp[10010],missile[10010];
 4 int main(){
 5     int N,max;
 6     while(~scanf("%d",&N)){max=0;
 7         for(int i=0;i<N;++i){dp[i]=1;
 8             scanf("%d",&missile[i]);
 9             for(int j=0;j<i;j++){
10                 if(missile[j]<missile[i])dp[i]=MAX(dp[j]+1,dp[i]);
11             }
12             max=MAX(max,dp[i]);
13         }
14         printf("%d\n",max);
15     }
16     return 0;
17 }

方法二:blog

二分法+貪心:ip

 

 1 #include<stdio.h>
 2 int missile[10010],Lis[10010];
 3 int r;
 4 void search(int x){
 5     int left=1,mid,right=r;
 6     while(left<=right){
 7         mid=(left+right)/2;//把 / 換成 >> 總是陷入死循環。。。。。 
 8         if(Lis[mid]<x)left=mid+1;
 9         else right=mid-1;
10     }
11     Lis[left]=x;
12 }
13 int main(){
14     int N;
15     while(~scanf("%d",&N)){r=1;
16     scanf("%d",&missile[0]);Lis[r]=missile[0];
17         for(int i=1;i<N;i++){
18             scanf("%d",&missile[i]);
19             if(missile[i]>Lis[r])Lis[++r]=missile[i];
20             else search(missile[i]);
21         }
22         printf("%d\n",r);
23     }
24     return 0;
25 }

方法三:開發

STL+二分+貪心:get

 

 1 #include<stdio.h>
 2 #include<algorithm>
 3 using namespace std;
 4 int Lis[10010]; 
 5 int main(){
 6     int N,r,x;
 7     while(~scanf("%d",&N)){r=0;
 8         scanf("%d",&x);
 9         Lis[r]=x;
10         for(int i=1;i<N;++i){
11             scanf("%d",&x);
12             if(x>Lis[r])Lis[++r]=x;
13             else *lower_bound(Lis,Lis+r,x)=x; 
14         }
15         printf("%d\n",r+1);
16     }
17     return 0;
18 }

 

方法四:it

vector+二分+貪心:

 

 1 #include<stdio.h>
 2 #include<vector>
 3 #include<algorithm>
 4 using namespace std;
 5 int main(){
 6     int N,x;
 7     while(~scanf("%d",&N)){
 8         vector<int>Lis;vector<int>::iterator iter;
 9         while(N--){
10             scanf("%d",&x);
11             iter=lower_bound(Lis.begin(),Lis.end(),x);
12             if(iter==Lis.end())Lis.push_back(x);
13             else *iter=x;
14         }
15         printf("%d\n",Lis.size());
16     }
17     return 0;
18 }
相關文章
相關標籤/搜索