最长公共子序列问题

【题目】

给定两个字符串str1和str2,返回两个字符串的最长公共子序列。

【举例】

str1=”1A2C3D4B56”
str2=”B1D23CA45B6A”
“123456”或者”12C4B6”都是最长公共子序列,返回哪个都行。

【代码】

    public static void main(String[] args) {
        String str1="1A2C3D4B56";
        String str2="B1D23CA45B6A";
        System.out.println(lcse(str1,str2));//123456
    } 

    //最长公共子序列问题
    //获得公共序列长度
    public static int[][] getdp(char[] str1,char[] str2){
        int[][] dp=new int[str1.length][str2.length];
        //dp[i][j]代表:str1[0..i]与str2[0..j]最长公共子序列的长度
        dp[0][0]=str1[0]==str2[0]?1:0;
        for(int i=1;i<str1.length;i++){//第1列,str1[0..i]与str2[0]公共长度
            dp[i][0]=Math.max(dp[i-1][0], str1[i]==str2[0]?1:0);
        }
        for(int j=1;j<str2.length;j++){//第1行,str1[0]与str2[0..j]公共长度
            dp[0][j]=Math.max(dp[0][j-1], str1[0]==str2[j]?1:0);
        }
        for(int i=1;i<str1.length;i++){
            for(int j=1;j<str2.length;j++){
                dp[i][j]=Math.max(dp[i-1][j], dp[i][j-1]);
                if(str1[i]==str2[j]){
                    dp[i][j]=Math.max(dp[i][j], dp[i-1][j-1])+1;
                }
            }
        }
        return dp;
        //矩阵右下角的值:两个str整体的最长公共子序列的长度
    }

    public static String lcse(String str1,String str2){
        if(str1==null || str2==null || str1.equals("") || str2.equals("")){
            return "";
        }
        char[] chs1=str1.toCharArray();
        char[] chs2=str2.toCharArray();
        int[][] dp=getdp(chs1,chs2);
        int m=chs1.length-1;
        int n=chs2.length-1;
        char[] res=new char[dp[m][n]];
        int index=res.length-1;
        //从矩阵的右下角开始移动,移动方式:向上、向左、左上
        while(index>=0){
            if(n>0 && dp[m][n]==dp[m][n-1]){
                n--;//左移
            }
            else if(m>0 && dp[m][n]==dp[m-1][n]){
                m--;//上移
            }else{
                //如果dp[i][j]>Math.max(dp[i-1][j],dp[i][j-1])
                //说明dp[i][j]=dp[i-1][j-1]+1
                //可以确定str1[i]=str2[j],且这个字符属于最长公共子序列,放进res
                res[index--]=chs1[m];//公共字符
                m--;
                n--;
            }
        }
        return String.valueOf(res);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值