LCS

作者: yuansip | 来源:发表于2016-11-01 14:02 被阅读0次

    LCS问题有两种,一是最长公共子序列, 二是最长公共子串,两者的区别是子序列的每个元素在原集合中不必是紧邻的,只要保持相对位置即可,而子串的每个元素在原集合中必须是紧邻的,比如:集合A { 4 5 7 5 9 3 2 3 1 9 }, 集合B { 1 2 5 7 2 },则集合A,B的最长公共子序列是{ 5 7 2 },最长公共子串是{ 5 7 }。LCS是可以用动态规划求解的经典问题。
    引申问题: 最长递增子串,最大子串和,最大子串积 (类似最大子串和,不过需要考虑符号问题)

    示例代码

    import java.util.Random;
    
    class LCS {
    
        private static void printArray(int[] arr) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < arr.length; i++) {
                sb.append(arr[i]);
                sb.append(' ');
            }
            sb.append('\n');
            System.out.print(sb.toString());
        }
    
        private static void fillArray(int[] arr) {
            final int MAX = 10;
            Random rand = new Random();
            for (int i = 0; i < arr.length; i++) {
                arr[i] = rand.nextInt(MAX);
            }
        }
    
        // 最长公共子序列
        private static int lcs(int i, int j, int[] ai, int[] aj, int[][] dtRecord) {
            if (i < 0 || j < 0) {
                return 0;
            }
            if (dtRecord[i][j] >= 0) {
                return dtRecord[i][j];
            }
            if (i == 0 && j == 0) {
                return ai[i] == aj[j] ? 1 : 0;
            }
            if (ai[i] == aj[j]) {
                dtRecord[i][j] = lcs(i - 1, j - 1, ai, aj, dtRecord) + 1;
            } else {
                dtRecord[i][j] = Math.max(lcs(i - 1, j, ai, aj, dtRecord), lcs(i, j - 1, ai, aj, dtRecord));
            }
            return dtRecord[i][j];
        }
    
        // 最长公共子串
        private static void lcs2(int[] ai, int[] aj) {
            int endI = -1;
            int endJ = -1;
            int maxLength = 0;
            int[][] dt = new int[ai.length][aj.length];
            for (int i = 0; i < ai.length; i++) {
                dt[i][0] = ai[i] == aj[0] ? 1 : 0;
                if (dt[i][0] > maxLength) {
                    endI = i;
                    endJ = 0;
                    maxLength = dt[i][0];
                } 
            }
            for (int j = 0; j < aj.length; j++) {
                dt[0][j] = aj[j] == ai[0] ? 1 : 0;
                if (dt[0][j] > maxLength) {
                    endI = 0;
                    endJ = j;
                    maxLength = dt[0][j];
                } 
            }
            for (int i = 1; i < ai.length; i++) {
                for (int j = 1; j < aj.length; j++) {
                    dt[i][j] = ai[i] == aj[j] ? dt[i-1][j-1] + 1 : 0;
                    if (dt[i][j] > maxLength) {
                        endI = i;
                        endJ = j;
                        maxLength = dt[i][j];
                    }
                }
            }
            System.out.println("LCS2=" + maxLength + " endI=" + endI + " endJ=" + endJ);
        }
    
        public static void main(String[] argv) {
            final int row = 5;
            final int column = 10;
            int[] x = new int[column];
            int[] y = new int[row];
            fillArray(x);
            printArray(x);
            fillArray(y);
            printArray(y);
            int[][] dt = new int[row][column];
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < column; j++) {
                    dt[i][j] = -1;
                }
            }
            System.out.println("LCS = " + lcs(row - 1, column - 1, y, x, dt));
            lcs2(x, y);
        }
    }
    

    参考阅读

    动态规划算法之最长公共子序列&最长公共子串
    程序员面试100题之最长公共子串

    相关文章

      网友评论

          本文标题:LCS

          本文链接:https://www.haomeiwen.com/subject/ensmuttx.html