算法题目总结 -- 最长公共子序列

问题描述

在两个字符串中,有些字符会一样,可以形成的子序列也有可能相等,因此,长度最长的相等子序列便是两者间的最长公共字序列,其长度可以使用动态规划来求。以s1={1,3,4,5,6,7,7,8},s2={3,5,7,4,8,6,7,8,2}为例。

最长公共子序列最长公共子串问题的区别为:
子序列意味着子串可以不必在母串中连续存在

解题思路

在这里插入图片描述

求最长子序列长度

两个字符串对应的最长公共子序列不一定唯一,这个程序输出所有的LCS内容。

基本思想是:
在这里插入图片描述
在这里插入图片描述

代码

/*

* lcs算法

* 子序列意味着子串可以不必在母串中连续存在

* */

public class LongestCommonSubSequence {



    /**

     *

     * @param str1

     * @param str2

     * @return 最长公共子序列的长度

     */

    public static int getLongestCommonSubSequence(String str1, String str2){

        int[][] subResult = new int[str1.length()+1][str2.length()+1];



        for (int i = 1; i < str1.length()+1; i++) {

            for (int j = 1; j < str2.length()+1; j++) {



                if (str1.charAt(i-1) == str2.charAt(j-1)){

                    subResult[i][j] = subResult[i-1][j-1] + 1;

                }else{

                    subResult[i][j] = Math.max(subResult[i][j-1], subResult[i-1][j]);

                }

            }

        }

//        for (int i = 0; i < str1.length()+1; i++) {

//            for (int j = 0; j < str2.length()+1; j++)

//                System.out.print(subResult[i][j] + " ");

//            System.out.println();

//        }

//        System.out.println(printLCS(str1, str2, subResult));





        HashSet<String> allLcs = new HashSet<>();

        printAllLCS(str1, str2, subResult, str1.length(), str2.length(), "", allLcs);

        System.out.println(allLcs);





        return subResult[str1.length()][str2.length()];

    }



    /**

     *

     * @param str1

     * @param str2

     * @param subResult

     * @return 其中一个公共子序列

     */

    public static String printLCS(String str1, String str2, int[][] subResult){

        String subStr = "";

        int i=str1.length(), j=str2.length();

        while (i>0 && j>0){

            if (str1.charAt(i-1) == str2.charAt(j-1)){

                subStr = str1.charAt(i-1) + subStr;

                i--;j--;

            }else if (subResult[i-1][j] >= subResult[i][j-1]){

                i--;

            }else {

                j--;

            }

        }



        return subStr;

    }



    public static void printAllLCS(String str1, String str2, int[][] subResult, int i, int j, String comSubStr, HashSet<String> allLcs){

        while (i>0 && j>0){

            if (str1.charAt(i-1) == str2.charAt(j-1)){

                comSubStr = str1.charAt(i-1) + comSubStr;

                i--;j--;

            }else if (subResult[i-1][j] > subResult[i][j-1]){

                i--;

            }else if (subResult[i-1][j] < subResult[i][j-1]){

                j--;

            }else{

                printAllLCS(str1, str2, subResult, i-1, j, comSubStr, allLcs);

                printAllLCS(str1, str2, subResult, i, j-1, comSubStr, allLcs);

                return;

            }

        }

        allLcs.add(comSubStr);

//        System.out.println(comSubStr);

    }



    public static void main(String[] args) {

        String str1 = "A1B2C3D";

        String str2 = "A2BC";

        System.out.println(getLongestCommonSubSequence(str1, str2));

    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值