Leetcode1143. 最长公共子序列

64 阅读2分钟

第一遍:暴力递归

不出所料,超时了。但是思路是没有错的。

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        char[] a = text1.toCharArray();
        char[] b = text2.toCharArray();
        return process(a, b, a.length - 1, b.length - 1);
    }
    
    // text1 : 0-i text:0-j 这个范围内的最长公共子序列的长度
    int process(char[] text1, char[] text2, int i, int j){
        if (i == 0 && j == 0) {
            return text1[0] == text2[0] ? 1 : 0;
        } else if (i == 0) {
            if (text2[j] == text1[i]) {
                return 1;
            } else {
                return process(text1, text2, i, j - 1);
            }
        } else if (j == 0) {
            if (text1[i] == text2[j]) {
                return 1;
            } else {
                return process(text1, text2, i - 1, j);
            }
        }
        
        //下面是二者都不为0
        //p1: 不以i结尾,不以j结尾 p2: 不以j结尾 p3:不以i结尾 p4:以i和j结尾
        int p1 = process(text1, text2, i - 1, j - 1);
        int p2 = process(text1, text2, i, j - 1);
        int p3 = process(text1, text2, i - 1, j);
        int p4 = 0;
        if (text1[i] == text2[j]) {
            p4 = p1 + 1;
        }
        return Math.max(Math.max(p3,p4), Math.max(p1,p2));
    }
}

因为解法中存在大量的重复解,所以可以改为动态规划。变化的参数只有i和j,因此可以建立一个二维数组,长度为M*N(M为text1的长度,N为text2的长度)。

通过分析暴力递归过程可知,dp[i][j]依赖的位置有左上角元素,左面元素和上面元素。因此dp数组从左上往右下构建。

第二遍,改为动态规划

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        char[] a = text1.toCharArray();
        char[] b = text2.toCharArray();
        int alen = a.length;
        int blen = b.length;
        int[][] dp = new int[alen][blen];
        if (a[0] == b[0]) dp[0][0] = 1;
        for (int j = 1; j < blen; j++) {
            dp[0][j] = a[0] == b[j] ? 1 : dp[0][j - 1];
        }
        
        for (int i = 1; i < alen; i++) {
            dp[i][0] = b[0] == a[i] ? 1 : dp[i - 1][0];    
        }
        for (int i = 1; i < alen; i++)
            for (int j = 1; j < blen; j++) {
                int p1 = dp[i-1][j - 1];
                int p2 = dp[i - 1][j];
                int p3 = dp[i][j - 1];
                
                if (a[i] == b[j]) {
                    p1 = p1 + 1;
                }
                dp[i][j] = Math.max(p3, Math.max(p1,p2));
            }
        return dp[alen - 1][blen - 1];
    }
}

运行结果:

最长公共子序列结果.png