Java两个字符串的最长公共子串 KMP算法

1. 引言

在字符串处理中,经常需要找到两个字符串中的最长公共子串。最长公共子串是指在两个字符串中同时出现的最长的子串。比如,字符串 "ABCXYZ" 和 "XYZDEF" 的最长公共子串是 "XYZ"。

本篇文章将介绍如何使用KMP算法来解决这个问题。KMP算法是一种高效的字符串匹配算法,它的核心思想是避免不必要的比较,提高匹配效率。在解决最长公共子串问题时,我们可以利用KMP算法来找到两个字符串的公共子串。

2. KMP算法简介

KMP算法由三位计算机科学家D.E.Knuth、J.H.Morris和V.R.Pratt于1977年联合提出,它的全称是Knuth-Morris-Pratt算法。KMP算法通过预处理模式串(即匹配串)构建一个部分匹配表(Partial Match Table),然后利用这个表来快速定位模式串在目标串中的位置。

KMP算法的基本思想是,当遇到不匹配的字符时,不需要回溯,而是根据部分匹配表中的信息,将模式串向后移动一定的距离,继续匹配。这样可以避免在每次不匹配时,都从目标串的下一个字符开始重新匹配。

3. KMP算法在最长公共子串中的应用

KMP算法在最长公共子串问题中的应用相对简单。我们可以将其中一个字符串作为模式串,另一个字符串作为目标串,然后利用KMP算法来匹配模式串在目标串中的位置。

具体步骤如下:

  1. 构建模式串的部分匹配表。
  2. 遍历目标串,利用KMP算法匹配模式串在目标串中的位置。
  3. 根据匹配的位置,找到最长公共子串。

下面是使用Java实现的KMP算法的例子:

public class KMPAlgorithm {
    public static String findLongestCommonSubstring(String str1, String str2) {
        String pattern = str1;
        String text = str2;

        int[] table = buildTable(pattern);
        int matchIndex = 0;
        int longestSubstringLength = 0;

        for (int i = 0; i < text.length(); i++) {
            while (matchIndex > 0 && pattern.charAt(matchIndex) != text.charAt(i)) {
                matchIndex = table[matchIndex - 1];
            }
            if (pattern.charAt(matchIndex) == text.charAt(i)) {
                matchIndex++;
                longestSubstringLength = Math.max(longestSubstringLength, matchIndex);
            }
        }

        return str1.substring(0, longestSubstringLength);
    }

    private static int[] buildTable(String pattern) {
        int[] table = new int[pattern.length()];
        int prefixIndex = 0;
        int suffixIndex = 1;

        while (suffixIndex < pattern.length()) {
            if (pattern.charAt(prefixIndex) == pattern.charAt(suffixIndex)) {
                table[suffixIndex] = prefixIndex + 1;
                prefixIndex++;
                suffixIndex++;
            } else if (prefixIndex > 0) {
                prefixIndex = table[prefixIndex - 1];
            } else {
                table[suffixIndex] = 0;
                suffixIndex++;
            }
        }

        return table;
    }

    public static void main(String[] args) {
        String str1 = "ABCXYZ";
        String str2 = "XYZDEF";
        String longestCommonSubstring = findLongestCommonSubstring(str1, str2);
        System.out.println("Longest common substring: " + longestCommonSubstring);
    }
}

4. 序列图

下面是使用mermaid语法绘制的KMP算法的序列图:

sequenceDiagram
    participant Application
    participant KMPAlgorithm
    participant String

    Application->>KMPAlgorithm: 调用findLongestCommonSubstring方法
    KMPAlgorithm->>KMPAlgorithm: 构建模式串的部分匹配表
    KMPAlgorithm->>KMPAlgorithm: 遍历目标串,匹配模式串
    KMPAlgorithm->>String: 返回最长公共子串