是n個(gè)不同的實(shí)數(shù)的序列,L的遞增子序列是這樣一個(gè)子序列Lin=

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

[zz]最長遞增子序列的求法 LIS

系統(tǒng) 1932 0

什么是最長遞增子序列呢?
問題描述如下:
?? 設(shè)L=<a1,a2,…,an>是n個(gè)不同的實(shí)數(shù)的序列,L的遞增子序列是這樣一個(gè)子序列Lin=<aK1,ak2,…,akm& gt;,其中k1<k2<…<km且aK1<ak2<…<akm。求最大的m值。
對(duì)于這個(gè)問題有以下幾種解決思路:
?? 1、把a(bǔ)1,a2,...,an排序,假設(shè)得到a'1,a'2,...,a'n,然后求a的a'的最長公共子串,這樣總的時(shí)間復(fù)雜度為o(nlg(n))+o(n^2)=o(n^2);
?? 2、動(dòng)態(tài)規(guī)劃的思路:
??? 另設(shè)一輔助數(shù)組b,定義b[n]表示以a[n]結(jié)尾的最長遞增子序列的長度,則狀態(tài)轉(zhuǎn)移方程如下:b[k]=max(max(b[j]|a[j]<a[k],j<k)+1,1);
??? 這個(gè)狀態(tài)轉(zhuǎn)移方程解釋如下:在a[k]前面找到滿足a[j]<a[k]的最大b[j],然后把a(bǔ)[k]接在它的后面,可得到a[k]的最長遞增子序 列的長度,或者a[k]前面沒有比它小的a[j],那么這時(shí)a[k]自成一序列,長度為1.最后整個(gè)數(shù)列的最長遞增子序列即為max(b[k]?? | 0<=k<=n-1);
??? 實(shí)現(xiàn)代碼如下:
????

#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]結(jié)尾的最長遞增子序列長度為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++)// 求出整個(gè)數(shù)列的最長遞增子序列的長度

???????????????????? if(b[i]>max)

??????????????????????????? max=b[i];

????????????? cout<<max<<endl;

?????? }

?????? return 0;

}

??? 顯然,這種方法的時(shí)間復(fù)雜度仍為o(n^2);
?? 3、對(duì)第二種思路的改進(jìn):
??? 第二種思路在狀態(tài)轉(zhuǎn)移時(shí)的復(fù)雜度為o(n),即在找a[k]前面滿足a[j]<a[k]的最大b[j]時(shí)采用的是順序查找的方法,復(fù)雜度為o(n).
??? 設(shè)想如果能把順序查找改為折半查找,則狀態(tài)轉(zhuǎn)移時(shí)的復(fù)雜度為o(lg(n)),這個(gè)問題的總的復(fù)雜度就可以降到nlg(n).
??? 另定義一數(shù)組c,c中元素滿足c[b[k]]=a[k],解釋一下,即當(dāng)遞增子序列的長度為b[k]時(shí)子序列的末尾元素為c[b[k]]=a[k].
??? 先給出這種思路的代碼,然后再對(duì)其做出解釋。
????

#include <iostream>

using namespace std;

int find(int *a,int len,int n)//若返回值為x,則a[x]>=n>a[x-1]

{

?????? int left=0,right=len,mid=(left+right)/2;

?????? while(left<=right)

?????? {

????????????? if(n>a[mid]) left=mid+1;

????????????? else if(n<a[mid]) right=mid-1;

????????????? else return mid;

????????????? mid=(left+right)/2;

?????? }

?????? return left;

}

void fill(int *a,int n)

{

?????? for(int i=0;i<=n;i++)

????????????? a[i]=1000;

}

int main()

{

?????? int max,i,j,n,a[100],b[100],c[100];

?????? while(cin>>n)

?????? {

????????????? fill(c,n+1);

????????????? for(i=0;i<n;i++)

???????????????????? cin>>a[i];

????????????? c[0]=-1;//??? …………………………………………1

????????????? c[1]=a[0];//??????? ……………………………………2

????????????? b[0]=1;//???? …………………………………………3

????????????? for(i=1;i<n;i++)//??????? ………………………………4

????????????? {

???????????????????? j=find(c,n+1,a[i]);//?? ……………………5

???????????????????? c[j]=a[i];// ………………………………6

???????????????????? b[i]=j;//……………………………………7

????????????? }

????????????? for(max=i=0;i<n;i++)//………………………………8

???????????????????? if(b[i]>max)

??????????????????????????? max=b[i];

????????????? cout<<max<<endl;

?????? }

?????? return 0;

}

??? 對(duì)于這段程序,我們可以用算法導(dǎo)論上的loop invariants來幫助理解.
????loop invariant: 1、每次循環(huán)結(jié)束后c都是單調(diào)遞增的。(這一性質(zhì)決定了可以用二分查找)
?????????????????????????? 2、每次循環(huán)后,c[i]總是保存長度為i的遞增子序列的最末的元素,若長度為i的遞增子序

????????????????????????????????? 列有多個(gè),剛保存末尾元素最小的那個(gè).(這一性質(zhì)決定是第3條性質(zhì)成立的前提)
?????????????????????????? 3、每次循環(huán)完后,b[i]總是保存以a[i]結(jié)尾的最長遞增子序列。
????initialization:??? 1、進(jìn)入循環(huán)之前,c[0]=-1,c[1]=a[0],c的其他元素均為1000,c是單調(diào)遞增的;
?????????????????????????? 2、進(jìn)入循環(huán)之前,c[1]=a[0],保存了長度為1時(shí)的遞增序列的最末的元素,且此時(shí)長度為1

???????????????????????????????? 的遞增了序列只有一個(gè),c[1]也是最小的;
?????????????????????????? 3、進(jìn)入循環(huán)之前,b[0]=1,此時(shí)以a[0]結(jié)尾的最長遞增子序列的長度為1.
????maintenance:?? 1、若在第n次循環(huán)之前c是單調(diào)遞增的,則第n次循環(huán)時(shí),c的值只在第6行發(fā)生變化,而由

??????????????????????????????? c進(jìn)入循環(huán)前單調(diào)遞增及find函數(shù)的性質(zhì)可知(見find的注釋),

???????????????????????????????? 此時(shí)c[j+1]>c[j]>=a[i]>c[j-1],所以把c[j]的值更新為a[i]后,c[j+1]>c[j]>c[j-1]的性質(zhì)仍然成

??????????????????????????????? 立,即c仍然是單調(diào)遞增的;
?????????????????????????? 2、循環(huán)中,c的值只在第6行發(fā)生變化,由c[j]>=a[i]可知,c[j]更新為a[i]后,c[j]的值只會(huì)變

????????????????????????????????? 小不會(huì)變大,因?yàn)檫M(jìn)入循環(huán)前c[j]的值是最小的,則循環(huán)中把c[j]更新為更小的a[i],當(dāng)

???????????????????????????????? 然此時(shí)c[j]的值仍是最小的;
???????????????? ????????? 3、循環(huán)中,b[i]的值在第7行發(fā)生了變化,因?yàn)橛衛(wèi)oop invariant的性質(zhì)2,find函數(shù)返回值

??????????????????????????????? 為j有:c[j-1]<a[i]<=c[j],這說明c[j-1]是小于a[i]的,且以c[j-1]結(jié)尾的遞增子序列有最大的

?????????????????????????????? 長度,即為j-1,把a(bǔ)[i]接在c[j-1]后可得到以a[i]結(jié)尾的最長遞增子序列,長度為(j-1)+1=j;
????termination:?????? 循環(huán)完后,i=n-1,b[0],b[1],...,b[n-1]的值均已求出,即以a[0],a[1],...,a[n-1]結(jié)尾的最長遞

????????????????????????????? 增子序列的長度均已求出,再通過第8行的循環(huán),即求出了整個(gè)數(shù)組的最長遞增子序列。

????????? 仔細(xì)分析上面的代碼可以發(fā)現(xiàn),每次循環(huán)結(jié)束后,假設(shè)已經(jīng)求出c[1],c[2],c[3],...,c[len]的值,則此時(shí)最長遞增子序列的長度為len,因此可以把上面的代碼更加簡化,即可以不需要數(shù)組b來輔助存儲(chǔ),第8行的循環(huán)也可以省略。
????

#include <iostream>

using namespace std;

int find(int *a,int len,int n)//修改后的二分查找,若返回值為x,則a[x]>=n

{

?????? int left=0,right=len,mid=(left+right)/2;

?????? while(left<=right)

?????? {

????????????? if(n>a[mid]) left=mid+1;

????????????? else if(n<a[mid]) right=mid-1;

????????????? else return mid;

????????????? mid=(left+right)/2;

?????? }

?????? return left;

}

int main()

{

?????? int n,a[100],c[100],i,j,len;// 新開一變量len,用來儲(chǔ)存每次循環(huán)結(jié)束后c中已經(jīng)求出值的元素的最大下標(biāo)

?????? while(cin>>n)

?????? {

????????????? for(i=0;i<n;i++)

???????????????????? cin>>a[i];

????????????? b[0]=1;

????????????? c[0]=-1;

????????????? c[1]=a[0];

????????????? len=1;// 此時(shí)只有c[1]求出來,最長遞增子序列的長度為1.

????????????? for(i=1;i<n;i++)

????????????? {

???????????????????? j=find(c,len,a[i]);

???????????????????? c[j]=a[i];

???????????????????? if(j>len)// 要更新len,另外補(bǔ)充一點(diǎn):由二分查找可知j只可能比len大1

??????????????????????????? len=j;// 更新len

????????????? }

????????????? cout<<len<<endl;

?????? }

?????? return 0;

}

[zz]最長遞增子序列的求法 LIS


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: www国产视频 | 色干综合 | 精品综合 | 亚洲欧美日韩高清中文在线 | 成人免费观看一区二区 | 朴妮唛禁福利视频在线 | 在线观看国产精美视频 | 日韩综合图区 | 女色狠xx网18| 亚洲欧美香蕉在线日韩精选 | 中文字幕高清免费不卡视频 | 六月成人网 | 九九久久久久午夜精选 | dyav午夜片 | 欧美日韩亚洲国产无线码 | 成人久久18免费网址 | 久久综合九色综合91 | 天天谢天天干 | 欧美日韩高清在线 | 俺去鲁婷婷六月色综合 | 九色综合网 | 四虎国产精品免费视 | 人人艹在线 | 不卡国产视频 | 国产99在线 | 亚洲 | 日韩免费毛片 | 亚洲日本va中文字幕婷婷 | 国产亚洲精aa在线观看不卡 | 国产精品亚洲精品日韩已满 | 国产原创麻豆精品视频 | 夜夜操夜夜 | 天天干天天碰 | 免费视频网站一级人爱视频 | 久久99精品一级毛片 | 久久精品国产精品青草 | 欧美一级成人一区二区三区 | 波多野结衣视频一区 | 香蕉视频看片 | 中文字幕日韩女同互慰视频 | 久久男人 | 一级黄色毛片免费看 |