Java中如何使用函数实现字符串的匹配算法?
字符串匹配算法在计算机科学中有着非常广泛的应用,例如在文本编辑器、搜索引擎、数据压缩、图像处理等方面都需要使用字符串匹配算法。在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;
