欢迎访问宙启技术站
智能推送

Java中如何使用函数实现字符串的匹配算法?

发布时间:2023-06-23 00:00:45

字符串匹配算法在计算机科学中有着非常广泛的应用,例如在文本编辑器、搜索引擎、数据压缩、图像处理等方面都需要使用字符串匹配算法。在Java中,我们可以使用函数轻松实现字符串匹配算法。本文将分享常用的几种字符串匹配算法,包括暴力匹配法、KMP算法、BM算法和Sunday算法。

1. 暴力匹配法

暴力匹配算法也被称为朴素匹配算法,它是最简单的字符串匹配算法。具体来说,暴力匹配算法从文本串的 个字符开始与模式串的 个字符比较,如果匹配,则比较文本串的下一个字符是否与模式串的下一个字符匹配,依此类推,直到模式串的所有字符都被匹配或者出现不匹配的字符,然后继续在文本串的下一个字符上重复上述过程。

暴力匹配算法的时间复杂度为O(n*m),其中n为文本串的长度,m为模式串的长度。当模式串与文本串的长度相等时,时间复杂度最高,达到O(n^2),效率非常低,但当模式串较短时,暴力匹配算法的效率将会更快。

以下是使用Java语言实现的暴力匹配算法代码:

public static int violenceMatch(String str1, String str2) {

    int len1 = str1.length();

    int len2 = str2.length();

    int i = 0; // str1的下标

    int j = 0; // str2的下标

    while (i < len1 && j < len2) {

        if (str1.charAt(i) == str2.charAt(j)) {

            // 如果当前字符匹配成功,则将两个下标都加1

            i++;

            j++;

        } else {

            // 如果匹配失败,则i回溯到上一次匹配成功的位置+1处

            i = i - j + 1;

            // j回到模式串的开头

            j = 0;

        }

    }

    // 匹配成功,返回模式串在文本串中 次出现的位置;否则返回-1

    if (j == len2)

        return i - j;

    else

        return -1;

}

2. KMP算法

KMP算法(Knuth-Morris-Pratt算法)是一种字符串匹配算法,它的时间复杂度为O(n+m),其中n为文本串的长度,m为模式串的长度。相比于暴力匹配法,KMP算法能够跳过一些已经匹配过的字符,在匹配较长字符串时效率更高。

KMP算法基于一个优化函数next[],它保存了模式串中前缀子串的最长公共前后缀长度。KMP算法的匹配过程中,文本串和模式串开始匹配时,如果遇到不匹配的字符,就会根据next[]数组中保存的返回值决定模式串向右移动多少个字符,以此类推,直到模式串被匹配或者文本串被检查完毕。

以下是使用Java语言实现的KMP算法代码:

public static int kmpMatch(String str1, String str2) {

    int len1 = str1.length();

    int len2 = str2.length();

    int i = 0; // str1的下标

    int j = 0; // str2的下标

    int[] next = getNext(str2); // 获取next数组

    while (i < len1 && j < len2) {

        if (j == -1 || str1.charAt(i) == str2.charAt(j)) {

            // 如果当前字符匹配成功,则将两个下标都加1

            i++;

            j++;

        } else {

            // 如果匹配失败,则i不变,j移到next[j]的位置

            j = next[j];

        }

    }

    // 匹配成功,返回模式串在文本串中 次出现的位置;否则返回-1

    if (j == len2)

        return i - j;

    else

        return -1;

}

public static int[] getNext(String str) {

    int len = str.length();

    int[] next = new int[len];

    int k = -1;

    int j = 0;

    next[0] = -1;

    while (j < len - 1) {

        if (k == -1 || str.charAt(j) == str.charAt(k)) {

            k++;

            j++;

            next[j] = k;

        } else {

            k = next[k];

        }

    }

    return next;

}

3. BM算法

BM算法(Boyer-Moore算法)是一种高效的字符串匹配算法,它的时间复杂度为O(n),其中n为文本串的长度,是目前已知的最优字符串匹配算法之一。BM算法的核心思想是向右移动模式串,从而尽量减少匹配次数。

BM算法分为两个阶段: 阶段,我们需要根据模式串中每个字符的出现位置、长度以及模式串自身的特点来预处理出移动长度表和好后缀规则表。第二阶段,我们根据预处理结果,对文本串进行匹配操作,每次根据移动长度表和好后缀规则表选择合适的移动方案,以此来进行优化。

以下是使用Java语言实现的BM算法代码:

public static int bmMatch(String str1, String str2) {

    int len1 = str1.length();

    int len2 = str2.length();

    int i = len2 - 1; // 模式串的下标

    int j = len2 - 1; // 文本串的下标

    int[] bc = generateBC(str2); // 获取bc表

    int[] gs = generateGS(str2); // 获取gs表

    while (i < len1 && j >= 0) {

        if (str1.charAt(i) == str2.charAt(j)) {

            i--;

            j--;

        } else {

            int x = bc[str1.charAt(i)];

            int y = j - gs[j + 1];

            i += Math.max(x, y);

            j = len2 - 1;

        }

    }

    // 匹配成功,返回模式串在文本串中 次出现的位置;否则返回-1

    if (j == -1)

        return i + 1;

    else

        return -1;

}

private static int[] generateBC(String str) {

    int[] bc = new int[256]; // 初始化

    int len = str.length();

    for (int i = 0; i < len; i++) {

        int ascii = str.charAt(i); // 计算每个字符的ASCLL码

        bc[ascii] = i; // 填充bc表

    }

    return bc;

}

private static int[] generateGS(String str) {

    int[] gs = new int[str.length()]; // 初始化

    int[] suffix = new int[str.length()]; // 初始化

    boolean[] prefix = new boolean[str.length()]; // 初始化

    for (int i = 0; i < str.length(); i++) {

        suffix[i] = -1;

        prefix[i] = false;

    }

    // 生成suffix和prefix数组

    for (int i = 0; i < str.length() - 1; i++) {

        int j = i;

        int k = 0;

        while (j >= 0 && str.charAt(j) == str.charAt(str.length() - 1 - k)) {

            j--;

            k++;

            suffix[k] = j + 1;

        }

        if (j == -1) prefix[k] = true;

    }

    // 填充gs表

    for (int i = 0; i < str.length(); i++) {

        gs[i] = -1;