舉著見過的例子要說明吧!
假設一個序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出來它的LIS長度為5.下面慢慢的一步一步的找出它的LIS.
我們定義一個了序列為B,然後用i從1到9慢慢的考察。另外再定義一個len來記錄當前的最長序列的長度
首先,把d[1]有序地放到B裡,令B[1] = 2,就是說當只有一個數字為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)~!
上面例子的代碼如下:
#include<iostream>using namespace std;int find(int *a,int len,int n){int left=0,right=len,mid=(right+left)/2;while(left<=right){if(n>a[mid])left=mid+1;else if(n<a[mid])right=mid-1;elsereturn mid;mid=(right+left)/2;}return left;}int main(){int c[100],i,j,len;int a[9]={2 ,1 ,5 ,3 ,6 ,4 ,8 ,9 ,7};c[0]=-1;c[1]=a[0];len=1;for(i=0;i<9;i++){j=find(c,len,a[i]);c[j]=a[i];if(j>len)len=j;}cout<<len<<endl;return 0;}