最长公共子串

引言

在计算机科学中,求解字符串的最长公共子串是一种常见的问题。最长公共子串是指在两个或多个字符串中出现的最长的连续子串。这个问题有着广泛的应用,比如DNA序列的比对、自然语言处理中的词语匹配等。本文将介绍最长公共子串问题的定义、解法以及相关的代码示例。

定义

给定两个字符串A和B,最长公共子串是指同时在A和B中出现的最长的连续子串。例如,对于字符串"ABCD"和"ACDF",它们的最长公共子串是"CD"。

暴力解法

最简单的解决方法是使用暴力枚举。具体思路是对于字符串A的每个字符,以及字符串B的每个字符,分别检查以它们为起点的所有连续子串是否相同。这种方法的时间复杂度为O(n^3),n为字符串的长度。

下面是一段用Java实现的暴力解法的代码示例:

public class LongestCommonSubstring {
    public static String longestCommonSubstring(String A, String B) {
        int m = A.length();
        int n = B.length();
        String longestSubstring = "";
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                int k = 0;
                while (i + k < m && j + k < n && A.charAt(i + k) == B.charAt(j + k)) {
                    k++;
                }
                if (k > longestSubstring.length()) {
                    longestSubstring = A.substring(i, i + k);
                }
            }
        }
        
        return longestSubstring;
    }
}

动态规划解法

暴力解法的时间复杂度较高,如果字符串长度较大,会导致运行时间过长。动态规划是一种优化的解法,它将问题拆分成更小的子问题并保存中间结果,以避免重复计算。

定义一个二维数组dp,其中dp[i][j]表示以A的第i个字符和B的第j个字符结尾的最长公共子串的长度。当A[i]等于B[j]时,dp[i][j]等于dp[i-1][j-1]加1;否则,dp[i][j]等于0。最后,最长公共子串的长度即为dp数组中的最大值。

下面是一段用Java实现的动态规划解法的代码示例:

public class LongestCommonSubstring {
    public static String longestCommonSubstring(String A, String B) {
        int m = A.length();
        int n = B.length();
        int[][] dp = new int[m+1][n+1];
        int maxLength = 0;
        int endIndex = 0;  // 最长公共子串在A中的结束索引
        
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (A.charAt(i-1) == B.charAt(j-1)) {
                    dp[i][j] = dp[i-1][j-1] + 1;
                    if (dp[i][j] > maxLength) {
                        maxLength = dp[i][j];
                        endIndex = i - 1;
                    }
                }
            }
        }
        
        return A.substring(endIndex - maxLength + 1, endIndex + 1);
    }
}

示例

下面是一个使用最长公共子串算法的示例:

public class Main {
    public static void main(String[] args) {
        String A = "ABCD";
        String B = "ACDF";
        
        String longestSubstring = LongestCommonSubstring.longestCommonSubstring(A, B);
        
        System.out.println("最长公共子串是:" + longestSubstring);
    }
}

输出结果为:

最长公共子串是:CD

总结

最长公共子串是一个常见的计算机科学问题,它可以通过暴力枚举和动态规划两种方法来解决。暴力枚举的时间复杂度较高,而动态规划通过保存中间结果来优化性能。在实际应用中,我们可以根据具