zoukankan      html  css  js  c++  java
  • 最长公共子序列问题;打印最长公共子序列及打印所有解问题

    package test;

    import java.util.Scanner;
    import java.util.TreeSet;

    public class algo {

    // 这里传参数字符数组,还可以是字符串
    public static int[][] getMaxLCSLength2(char [] arr1, char [] arr2){
    int len1 = arr1.length;
    int len2 = arr2.length;
    // 下面完全是根据LCS定义而走;首先处理边界的问题,需要存储0行0列;所以这里动态规划数组长度比原长度多1
    int [][] dp = new int[len1+1][len2+1];
    for(int i = 0;i<=len2;i++){ // 处理边界,注意是<=号
    dp[0][i] = 0;
    }
    for(int i = 0;i<=len1;i++){ //第i行,第0列全部为0 //这里是<=号
    dp[i][0] = 0;
    }
    for(int i = 1;i<=len1;i++){ //这里是<=号
    for(int j = 1;j<=len2;j++){ //这里是<=号
    if(arr1[i-1] == arr2[j-1]){//注意这里若是arr1[i] == arr2[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[len1][len2]; 返回最长子序列长度
    return dp;
    }

    public static void traceBack(int [][] dp, char [] arr1, char [] arr2, int i, int j, String lcs_str) {
    TreeSet<String> set = new TreeSet<String>();
    while (i>0 && j>0) {
    if (arr1[i-1] == arr2[j-1]) {
    lcs_str += arr1[i-1];
    i--;
    j--;
    }
    else {
    if (dp[i][j-1]>dp[i-1][j])
    j--;
    else if (dp[i][j-1]<dp[i-1][j])
    i--;
    else { // 相等的情况;说明是相等
    traceBack(dp, arr1, arr2, i-1, j, lcs_str);
    traceBack(dp, arr1, arr2, i, j-1, lcs_str);
    return;
    }
    }
    }
    set.add(reverse(lcs_str));
    //输出最长公共子序列
    for(String s : set) {
    System.out.println(s);
    }
    }

    public static String reverse(String str) {
    StringBuffer strBuf = new StringBuffer(str).reverse();
    return strBuf.toString();
    }


    // 这个函数只是输出最长子序列;显然如果只是记录长度,则直接判断else(xi != yj) dp[i][j] = Math.max(dp[i][j - 1], dp[i -1][j])
    public static int maxlongest(String x, String y) {
    int xlen = x.length();
    int ylen = y.length();
    int [][]dp = new int[xlen + 1][ylen + 1];
    int [][]dir = new int[xlen + 1][ylen + 1];
    for(int i = 1; i <= xlen; i ++) {
    char xi = x.charAt(i - 1);
    for(int j = 1; j <= ylen; j ++) {
    char xj = y.charAt(j - 1);
    if(xi == xj) {
    dp[i][j] = dp[i - 1][j - 1] + 1;
    dir[i][j] = 2; // 2代表是左上
    }
    else if(dp[i - 1][j] > dp[i][j - 1])
    {
    dp[i][j] = dp[i - 1][j];
    dir[i][j] = 1; //1代表是向上
    }
    else {
    dp[i][j] = dp[i][j - 1];
    dir[i][j] = 3; //3代表是向左
    }
    }
    }


    int i = xlen;
    int j = ylen;
    StringBuffer sb = new StringBuffer();
    while (i > 0 && j > 0) {
    if (x.charAt(i - 1) == y.charAt(j - 1)) {
    sb.append(x.charAt(i - 1));
    i--;
    j--;
    } else {
    if (dp[i][j - 1] > dp[i - 1][j]) {//找大的那个方向,此处是左边大于上面,则该处的结果是来自左边
    j--;
    } else if (dp[i][j - 1] < dp[i - 1][j]) {
    i--;
    } else if (dp[i][j - 1] == dp[i - 1][j]) {
    // 如果是要打印所有的最长公共子序列,在这里进行保存,详细的见最上面
    i--; //此结果对于结果1所选取方向,str1的下标左移一位.替换为j--,则结果对应与结果2选取的方向
    }
    }
    }
    //由于是从后往前加入字符的,需要反转才能得到正确结果
    System.out.println(sb.reverse().toString());
    return dp[xlen][ylen];
    }

    public static void main(String[] args) {
    // 测试一:只打印一个最长公共子序列
    String x = "abcbdab";
    String y = "bdcaba";
    int len = maxlongest(x, y);
    System.out.print(len);

    // 测试二:打印所有最长公共子序列
    Scanner sc = new Scanner(System.in);
    String str1 = sc.nextLine();
    String str2 = sc.nextLine();
    char [] numsA = str1.toCharArray();
    char [] numsB = str2.toCharArray();
    int [][] dp = getMaxLCSLength2(numsA, numsB);
    int len1 = dp[numsA.length][numsB.length];
    String lcs_str = "";
    traceBack(dp, numsA, numsB, numsA.length,numsB.length,lcs_str);
    System.out.println(len1);


    }

    }

  • 相关阅读:
    python2与3自由切换
    ubuntu 安汉google浏览器
    ros 下常用的依赖库
    imu tool使用
    g2o 初始化
    linux 解压缩
    sudo apt-get update 没有公钥,无法验证下列签名
    ceres g2o 安装
    ubuntu 下开源安装
    Nhibernate中 Many-To-One 中lazy="proxy" 延迟不起作用的原因
  • 原文地址:https://www.cnblogs.com/xiezi1015/p/11633751.html
Copyright © 2011-2022 走看看