日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

【串和序列處理 7】LIS 最長(zhǎng)遞增子序列

 靜聽沙漏 2012-01-08

LIS:給定一個(gè)字符串序列S={x0,x1,x2,...,x(n-1)},找出其中的最長(zhǎng)子序列,而且這個(gè)序列必須遞增存在。

下面給出解決這個(gè)問(wèn)題的幾種方法:

(1) 轉(zhuǎn)化為L(zhǎng)CS問(wèn)題

思想:將原序列S遞增排序成序列T,然后利用動(dòng)態(tài)規(guī)劃算法取得S與T的公共最長(zhǎng)子序列。具體算法詳見《LCS最長(zhǎng)公共子序列》。

效率:這個(gè)方法排序最好的是時(shí)間復(fù)雜度是O(n*logn),動(dòng)態(tài)規(guī)劃解決LCS的時(shí)間復(fù)雜度是O(n^2)。因此總體時(shí)間復(fù)雜度是O(n*logn)+O(n^2)=O(n^2)級(jí)別。


(2) 分治策略

思想:假設(shè)f(i)表示S中 x0 ... xi 子串的最長(zhǎng)遞增子序列的長(zhǎng)度。則有如下遞歸:找到所有在xi之前,且值小于xi 的元素xj,即j<i 且 xj<xi。如果這樣的元素存在,那么所有的xj 都有一個(gè)x0 ... xj 子串的最長(zhǎng)遞增子序列,其長(zhǎng)度為f(j)。把其中最大的f(j)選出來(lái),則

f(i)=Max(f(j))+1. 其中{j | j<i 且xj<xi}

如果這樣的j不存在,則xi自身構(gòu)成一個(gè)長(zhǎng)度為1的遞增子序列。

該算法Java源代碼如下:

Java代碼
  1. package net.hr.algorithm.string;
  2. /**
  3. * 最長(zhǎng)遞增子序列 LIS
  4. * @author heartraid
  5. */
  6. public class LIS {
  7. char[] chars=null;
  8. public LIS(String str){
  9. chars=str.toCharArray();
  10. }
  11. public void getLIS(){
  12. int[] f=new int[chars.length]; //用于存放f(i)值
  13. String[] sequence=new String[chars.length];
  14. f[0]=1; //以第x1為末元素的最長(zhǎng)遞增子序列長(zhǎng)度為1
  15. for(int i=1;i<chars.length;i++)//循環(huán)n-1次
  16. {
  17. sequence[i]=""+chars[i];
  18. f[i]=1;//f[i]的最小值為1;
  19. String temp="";
  20. for(int j=0;j<i;j++)//循環(huán)i 次
  21. {
  22. if(chars[j]<chars[i]&&f[j]>f[i]-1){
  23. temp=temp+chars[j];
  24. f[i]=f[j]+1;//更新f[i]的值。
  25. }
  26. }
  27. sequence[i]=temp+sequence[i];
  28. }
  29. //打印結(jié)果
  30. int maxLength=0;
  31. int maxSize=0;
  32. for(int k=0;k<chars.length;k++){
  33. if(maxLength<f[k]){
  34. maxLength=f[k];
  35. maxSize=k;
  36. }
  37. }
  38. System.out.println("最大遞增子序列為:"+sequence[maxSize]+"(length="+maxLength+")");
  39. }
  40. public static void main(String[] args) {
  41. LIS lis=new LIS("ijabcsrewesdsdewg");
  42. lis.getLIS();
  43. }
  44. }

效率:算法時(shí)間復(fù)雜度為O(n^2)級(jí)別。

(3) 動(dòng)態(tài)規(guī)劃算法

實(shí)際上這是一道很典型的動(dòng)態(tài)規(guī)劃問(wèn)題。我們假設(shè)a[0]....a[i-1] 有一個(gè)最長(zhǎng)遞增子序列,其長(zhǎng)度f(wàn)(i-1)<=i, 且該最長(zhǎng)遞增子序列的最后一個(gè)元素為b。

那么對(duì)于a[0].... a[i] 而言,如果b<a[i],那么f(i)=f(i-1)+1,且最長(zhǎng)遞增子序列的最后一個(gè)元素變成了a[i]。如果b>=a[i],那么f(i)=f(i-1)。

上面的過(guò)程有一個(gè)難點(diǎn):如果a[0]....a[i-1] 有多個(gè)最大長(zhǎng)度為f(i-1)的遞增子序列怎么辦?需不需要所有長(zhǎng)度等于f(i-1)的遞增子序列的最后一個(gè)元素b0...bi全部存儲(chǔ)起來(lái),再一一和a[i]比較大小呢?如果是這樣,那么整個(gè)算法與上面的分治策略將沒(méi)有什么不同了?

事實(shí)上,并不需要怎么做。我們舉個(gè)例子: a[]={1、2、5、3、7}

a[0] ... a[3] 的最大遞增子序列有兩個(gè){1,2,5}和{1,2,3},當(dāng)增加a[4]的時(shí)候,如果a[4]>5,則兩個(gè)子序列都需要增加a[4];如果a[4]>3,則{1,2,3}+a[4]將必定成為新的最大子序列,而{1,2,5}不確定。因此我們看出,只要保存所有最大序列的最小的末尾元素即可。

因此我們?cè)O(shè)計(jì)一個(gè)如下的算法:其中b[k]用來(lái)表示最大子序列長(zhǎng)度為k時(shí)的最小末尾元素。

Java代碼 復(fù)制代碼 收藏代碼
  1. int LIS(){
  2. b[1]=a[0];
  3. for(int i=1;k=1;i<n;i++){
  4. if(a[i]>=b[k]) b[++k]=a[i];
  5. else b[binary(i,k)]=a[i];
  6. }
  7. return k;
  8. }
  9. int binary(int i, int k){
  10. if(a[i]<b[1]) return 1;
  11. for(int h=1,j=k;h!=j-1;){
  12. if(b[k=(h+j)/2]<=a[i]) h=k;
  13. else j=k;
  14. }
  15. return j;
  16. }

該算法的時(shí)間復(fù)雜為O(N*logN)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多