动态规划--3.最长公共子序列LCS和最长公共子字符串

来源:互联网 发布:机器人 毛笔字 算法 编辑:程序博客网 时间:2024/06/01 15:20

1.LCS:序列X{x1,x2,x3...xm}和序列Y{y1,y2...yn}找到两个序列的最长公共子序列是指X中的某些元素按照先后顺序出现在Y中,比如x1和x2出现在Y中,一定要x1在前x2在后,但二者可以不连续。 再比如BDCABA 和 ABCBDAB,字符串 BCBA 和 BDAB 都是是它们的最长公共子序列,则输出它们的长度4,并打印任意一个子序列

2.理解题意后我们设C[i,j]表示序列 x1,x2...xi 和序列 y1,y2...yn 的最长公共子序列,此处 i 和 j 分别为X Y最后元素的下标,那么:

(1)当i=0 || j=0时, C[i,j]=0 

(2)当 xi=yj时,C[i,j]=C[i-1,j-1] +1; 即两个序列最后一个元素都相等时,那么子序列=两个元素加入之前的情况+1

(3)当xi != yj 时,C[i,j]=max{ C[i-1,j] , C[i,j-1] }; 即当两个序列最后一个元素不等时,子序列=只加入Xi 不加入yj 和只加入yj 不加入xi的情况中的最大值 

3. 动态规划的时间复杂度=子问题的个数*每个子问题选择的种数,在lcsLength函数中时间复杂度为O(mn),在print函数中采用递归形式,时间复杂度为O(m+n)

/** *  */package lcs;/** * @author LingLee *动态规划 最长公共子序列问题 * */public class LCS {public static int[][] lcsLength(String x,String y){int[][] c=new int[x.length()][y.length()];//c[i][j]是用来记录序列x1...xi和序列y1...yn最长公共子序列的长度的int[][] b=new int[x.length()][y.length()];//b[i][j]记录表中走向的for(int i=0;i<x.length();i++) c[i][0]=0;for(int j=0;j<y.length();j++) c[0][j]=0;for(int i=1;i<x.length();i++){for(int j=1;j<y.length();j++){if(x.charAt(i)==y.charAt(j)){//当xi=yj时c[i][j]=c[i-1][j-1]+1;b[i][j]=1;//往左上角走}else if(c[i-1][j]>=c[i][j-1]){c[i][j]=c[i-1][j];b[i][j]=0;//往上走,或者说是往j的那一面走}else{c[i][j]=c[i][j-1];b[i][j]=-1;//往左走,或者说往靠近i的那一面走}}}System.out.println("最长公共子序列长度="+c[x.length()-1][y.length()-1]);return b;}public static void print(int[][] b,String x,int i,int j){if(i==0||j==0) return;if(b[i][j]==1){print(b,x,i-1,j-1);System.out.print(x.charAt(i)+"\t");}else if(b[i][j]==0){print(b,x,i-1,j);}else{print(b,x,i,j-1);}}public static void main(String[] args){String x=" ABCBDAB";//注意i和j是从1开始的,所以字符串的首个字符并没有参与比较String y=" BDCABA";int [][] b=lcsLength(x,y);print(b,x,x.length()-1,y.length()-1);}}

public class LCS {    public int findLCS(String s1, int n, String s2, int m) {        // write code here        int[][] dp=new int[n][m];//n*m列                //初始化         boolean temp=false;        for(int i=0;i<n;i++){//注意初始化部分,s[i]与s2[0]相等,那么i之后的所有子序列与s2[0]的公共子序列都是s[0]            if(s1.charAt(i)==s2.charAt(0)){                temp=true;            }             if(temp) dp[i][0]=1;            else dp[i][0]=0;        }        temp=false;        for(int i=0;i<m;i++){            if(s2.charAt(i)==s1.charAt(0)) temp=true;            if(temp) dp[0][i]=1;            else dp[0][i]=0;        }                        for(int i=1;i<n;i++){            for(int j=1;j<m;j++){                if(s1.charAt(i)==s2.charAt(j)) {                    dp[i][j]=dp[i-1][j-1]+1;                }                else dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);            }        }        return dp[n-1][m-1];    }}



二、最长公共子字符串

1.该问题和lcs唯一的不同是,公共子字符串要求元素字符按照先后顺序出现且是连续的。再比如BDCABA 和 ABCBDAB,最长公共子字符串为AB


0 0
原创粉丝点击