標籤:情況 順序 image 動態 nbsp har imp 子序列 rem
給定兩個字串,求其公用最長子序列。子序列與子串不同,子序列只需保證元素之間的相對順序與原字串一樣就行,不要求這些元素連續。如果這個問題用
暴力法來做,可以試想一下一個長為m與一個長為n的字串,要比較比較C(n,j)(j=1→n)與C(m,i)(i=1→m)是否有相同的並記錄最長的序列,總的比較次數為
C(n,1)*C(m,1)*1+C(n,2)*C(m,2)+...+C(n,j)*C(m,j)*j j=min(m,n)。如果用動態規劃來做,時間複雜度僅僅是O(mn)。
import java.util.LinkedList;public class LongestCommonSubsequence { public static void main(String[] args) { String s1="123456789"; String s2="724765626"; longestCommonSubsequence(s1,s2); } //求最長子序列的函數 public static void longestCommonSubsequence(String s1,String s2) { char[] arr1=s1.toCharArray(); char[] arr2=s2.toCharArray(); int m=arr1.length; int n=arr2.length; //c[i][j]表示arr1中元素0到i與arr2中元素0到j這兩個子串的最長公用子序列長度 int[][] c=new int[m+1][n+1]; //b[i][j]表示c[i][j]是怎麼來的,三種情況,下面詳細討論 String[][] b=new String[m+1][n+1]; //初始化c[][],因為空白字串和任意一個字串的最長公用子序列長度是0 for(int i=0;i<m;i++) c[m][0]=0; for(int i=0;i<n;i++) c[0][n]=0; for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++) { //如果兩字串i-1和j-1位置上的元素是相同的,則c[i][j]可以從它最近的左上值加1得到, if(arr1[i-1]==arr2[j-1]) { c[i][j]=c[i-1][j-1]+1; b[i][j]=""; } //如果不同,則c[i][j]取和它相鄰的上面或左面的最大值 else { if(c[i-1][j]>c[i][j-1]) { c[i][j]=c[i-1][j]; b[i][j]="↑"; } else { c[i][j]=c[i][j-1]; b[i][j]="←"; } } } } //用堆棧的形式儲存資料,方便結果的順序輸出 LinkedList<Character> l=new LinkedList<>(); while(b[m][n]!=null) { if(b[m][n].equals("")) { l.add(arr1[m-1]); m--; n--; } else if(b[m][n].equals("←")) n--; else if(b[m][n].equals("↑")) m--; } //輸出堆棧中的元素 while(l.size()!=0) { System.out.print(l.removeLast()); } }}
列印結果
動態規劃_公用最長子序列 java