LCS

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)