给定两个字符串求两个字符的最长公共子序列长度问题的解法

问题描述

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

思路

        思路一:使用递归的方式求解。用i1和i2表示现在所指向字符串中的位置。此题有四种大的情况:

  1. i1 == 0 && i2  == 0
  2. i1 == 0 &&  i2 != 0
  3. i1 != 0 && i2 == 0
  4. i1 != 0 && i2 != 0        

        在第四种情况中,我们们按照最长公共子序列结果中是否包含str1和str2结尾字符又可以分为四种小类:

        1. 结果中都不包含str1和str2结尾字符,记为p1。

        2. 结果中都包含str1结尾字符不包含str2结尾字符,记为p2。

        3.结果中都包含str2结尾字符不包含str1结尾字符,记为p3。

        4. str1和str2结尾字符相同,结果中包含str1和str2结尾字符,记为p4。

        思路二:根据思路一,我们可以进行动态规划求解。定义二维数组dp,其行表示str1字符串的每一个字符,列表示str2字符串的每一个字符,dp[i][j]表示str1到i字符与str2到字符的最长公共子序列的字符数。根据思路一的分析p1一定小于p2与p3中的任意一个,再求dp[i][j]值时就可以先把p2与p3的最大值暂时存在里面,我们判断该位置str1和str2字符是否相同,若相同再把刚才的值与p1加1的值取最大值存在dp[i][j]中,最后的结果就存在dp[i][j]中。

代码

    public static int lcs(String s1,String s2){
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();
        int N  = str1.length;
        int M = str2.length;
        return process(str1,str2,N-1,M-1);
    }

    public static int process(char[] str1,char[] str2,int i1,int i2){
        if (i1 == 0&& i2==0){
            return str1[i1]==str2[i2]?1:0;
        }
        if (i1==0){
            return ((str1[i1]==str2[i2])||process(str1,str2,i1,i2-1)==1)?1:0;
        }
        if (i2==0){
            return ((str1[i1]==str2[i2])||process(str1,str2,i1-1,i2)==1)?1:0;
        }

        int p1 = process(str1,str2,i1-1,i2-1);
        int p2 = process(str1,str2,i1,i2-1);
        int p3 = process(str1,str2,i1-1,i2);
        int p4 = 0;
        if (str1[i1]==str2[i2]){
            p4=p1+1;
        }
        return Math.max(Math.max(p1,p2),Math.max(p3,p4));
    }

    public static int dp(String s1,String s2){
        char[] str1 =s1.toCharArray();
        char[] str2 = s2.toCharArray();
        int N = str1.length;
        int M = str2.length;
        int[][] dp = new int[N][M];
        dp[0][0] = str1[0]==str2[0]?1:0;
        for (int i = 1;i<N;i++){
            dp[i][0] = str1[i] == str2[0]?1:dp[i-1][0];
        }
        for (int i = 1;i<M;i++){
            dp[0][i] = str1[0] == str2[i]?1:dp[0][i-1];
        }
        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[N-1][M-1];
    }

    public static void main(String[] args) {
        String str1 = "ab1c2";
        String str2 = "12op";
        System.out.println(lcs(str1,str2));
        System.out.println(dp(str1,str2));
    }

问题描述

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

代码

 

    public static String maxSubSequence(String str1,String str2){
        if (str1 ==null||str1.equals("")|| str2==null||str2.equals("")){
            return "";
        }
        char[] c1 = str1.toCharArray();
        char[] c2 = str2.toCharArray();
        int len1 = c1.length;
        int len2 = c2.length;
        int[][] dp = new int[len1][len2];

        //第一行
        for (int i = 0;i<len2;i++){
            dp[0][i]=c2[i]==c1[0]?1:dp[0][i-1];
        }
        //第一列
        for (int i = 0;i<len1;i++){
            dp[i][0] = c1[i]==c2[0]?1:dp[i-1][0];
        }

        for (int i = 1;i<len1;i++){
            for (int j =1;j<len2;j++){
                int p1 = 0;
                int p2 = 0;
                int p3 = 0;
                int p4 = 0;
                if (c1[i] == c2[i]){
                    p1 = dp[i-1][j-1]+1;
                }else if (c1[i-1] == c2[j]){
                    p2 =dp[i-1][j];
                }else if (c1[i] == c2[j-1]){
                    p3 = dp[i][j-1];
                }else {
                    p4 = dp[i-1][j-1];
                }
                dp[i][j] = Math.max(p1,Math.max(p2,Math.max(p3,p4)));
            }
        }

        int maxSubSeq = dp[len1-1][len2-1];
        char[] res = new char[maxSubSeq];
        int index = maxSubSeq -1;
        len1 = len1-1;
        len2 = len2-1;
        while (index>=0){
            if (len2>0&&dp[len1][len2]==dp[len1][len2-1]){
                len2--;
            }else if (len1 >0 && dp[len1][len2] ==dp[len1-1][len2]){
                len1--;
            }else {
                res[index--] = c1[len1];
                len1--;
                len2--;
            }
        }
        return String.valueOf(res);
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值