返回

动态规划最长公共子序列(LCS)问题(Java实现)及Java应用详解

后端

动态规划最长公共子序列(LCS)问题

问题分析

求最长公共子序列,先明白两个概念:

  • 子序列:一个给定序列中删去若干元素后得到的序列
  • 公共子序列:给定两个序列X,Y,当另一序列Z既是X的子序列,又是Y的子序列,则Z是X与Y的公共子序列

算法实现

基本思想

动态规划求最长公共子序列LCS的思想是:

  1. 把序列X和Y的第一个字符进行比较,若相等,则LCS(X,Y)=1+LCS(X[1...n], Y[1...n]),即把两个序列第一个字符删去后,求剩余子序列的LCS。
  2. 若不等,则LCS(X,Y)=max(LCS(X[1...n], Y),LCS(X,Y[1...n]),即取两个序列第一个字符都删去后,求剩余子序列的LCS的最大值。

Java实现

import java.util.Arrays;

public class LCS {

    public static void main(String[] args) {
        String X = "ABCDGH";
        String Y = "AEDFHR";
        int[][] c = new int[X.length() + 1][Y.length() + 1];
        int[][] b = new int[X.length() + 1][Y.length() + 1];
        int lcsLength = lcsLength(X, Y, c, b);
        System.out.println("LCS length: " + lcsLength);
        printLCS(X, Y, b);
    }

    public static int lcsLength(String X, String Y, int[][] c, int[][] b) {
        for (int i = 1; i <= X.length(); i++) {
            c[i][0] = 0;
        }
        for (int j = 0; j <= Y.length(); j++) {
            c[0][j] = 0;
        }
        for (int i = 1; i <= X.length(); i++) {
            for (int j = 1; j <= Y.length(); j++) {
                if (X.charAt(i - 1) == Y.charAt(j - 1)) {
                    c[i][j] = c[i - 1][j - 1] + 1;
                    b[i][j] = 1;
                } else {
                    if (c[i - 1][j] >= c[i][j - 1]) {
                        c[i][j] = c[i - 1][j];
                        b[i][j] = 2;
                    } else {
                        c[i][j] = c[i][j - 1];
                        b[i][j] = 3;
                    }
                }
            }
        }
        return c[X.length()][Y.length()];
    }

    public static void printLCS(String X, String Y, int[][] b) {
        int i = X.length();
        int j = Y.length();
        StringBuilder sb = new StringBuilder();
        while (i > 0 && j > 0) {
            if (b[i][j] == 1) {
                sb.append(X.charAt(i - 1));
                i--;
                j--;
            } else if (b[i][j] == 2) {
                i--;
            } else {
                j--;
            }
        }
        System.out.println("LCS: " + sb.reverse().toString());
    }
}