最长公共子序列; 给定两个字符串,返回两个字符串的最长公共子序列(不是最长公共子字符串),可能是多个。

最长公共子序列
Description

给定两个字符串,返回两个字符串的最长公共子序列(不是最长公共子字符串),可能是多个。

Input

输入第一行为用例个数, 每个测试用例输入为两行,一行一个字符串

Output

如果没有公共子序列,不输出,如果有多个则分为多行,按字典序排序。

Sample Input 1

1
1A2BD3G4H56JK
23EFG4I5J6K7

Sample Output 1

23G456K
23G45JK
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class Q1_1 {
    private static int T;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        T = in.nextInt();
        in.nextLine();
        while (T-- != 0) {
            String a = in.nextLine();
            String b = in.nextLine();

            Set<String> lcsSet = LCS(a, b);

            ArrayList<String> list = new ArrayList<>(lcsSet);
            if (list.size() == 1 && list.get(0).equals("")){
                continue;
            }
            list.sort(String::compareTo);
            for (int i = 0; i < list.size(); i++) {
                print(list.get(i), list.size()-1-i);
            }
        }
    }

    private static void print(String s, int n){
        if (T == 0 && n == 0){
            System.out.println(s);
        }else{
            System.out.println(s );
        }
    }

    public static Set<String> LCS(String a, String b) {
        int n = a.length(), m = b.length();
        //c[i][j]表示a长度为i和b长度为j时的最长公共子序列长度
        int[][] c = new int[n+1][m+1];
        //d[i][j]表示方向
        char[][] d = new char[n+1][m+1];
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= m; ++j) {
                if(a.charAt(i-1) == b.charAt(j-1)) {
                    c[i][j] = c[i-1][j-1] + 1;
                    //左上
                    d[i][j] = '↖';
                } else if(c[i-1][j] > c[i][j-1]){
                    c[i][j] = c[i-1][j];
                    //上
                    d[i][j] = '↑';
                } else if(c[i-1][j] < c[i][j-1]){
                    c[i][j] = c[i][j-1];
                    //左
                    d[i][j] = '←';
                } else {
                    c[i][j] = c[i][j-1];
                    //可向左可向右
                    d[i][j] = '┘';
                }
//                System.out.print(j == m ? c[i][j] + "\n":c[i][j] + " ");
            }
        }
//        for(int i = 0; i <= n; ++i){
//            for(int j = 0; j <= m; ++j) {
//                System.out.print(j == m ? d[i][j] + "\n":d[i][j] + " ");
//            }
//        }
        String lcs = "";
        Set<String> lcsSet = new HashSet<>();
        backTrace(d,a,lcs,n,m,c[n][m],lcsSet);

        return lcsSet;
    }

    public static void backTrace(char[][] d, String a, String lcs, int i , int j, int maxSublen, Set<String> lcsSet){
        if(i == 0 || j == 0) {
            StringBuilder sb = new StringBuilder(lcs);
            lcs = sb.reverse().toString();
            //可能有些提早出来了,一定要判断长度是最长的,但是这样还是会有重复的字符串,所以还要做去重处理
            if (lcs.length() == maxSublen) {
                lcsSet.add(lcs);
            }
            return;
        }

        switch (d[i][j]){
            case '↖':
                lcs += a.charAt(i-1);
                backTrace(d,a,lcs,i-1,j-1,maxSublen,lcsSet);
                break;
            case '↑':
                backTrace(d,a,lcs,i-1,j,maxSublen,lcsSet);
                break;
            case '←':
                backTrace(d,a,lcs,i,j-1,maxSublen,lcsSet);
                break;
            case '┘':
                backTrace(d,a,lcs,i-1,j,maxSublen,lcsSet);
                backTrace(d,a,lcs,i,j-1,maxSublen,lcsSet);
                break;
        }
    }

}

猜你喜欢

转载自www.cnblogs.com/billxxx/p/11768973.html