动态规划_公共最长子序列 java
给定两个字符串,求其公共最长子序列。子序列与子串不同,子序列只需保证元素之间的相对顺序与原字符串一样就行,不要求这些元素连续。如果这个问题用
暴力法来做,可以试想一下一个长为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()); } } }
打印结果