Java程序实现Zhu-Takaoka字符串匹配算法


Zhu-Takaoka算法是用于模式匹配的最佳算法之一。它结合了Boyer-Moore和KMP字符串匹配算法的优势。

Zhu-Takaoka算法利用良好的字符偏移和坏字符偏移技术来解决问题。

问题陈述 - 我们给定两个字符串。我们需要实现Zhu-Takaoka算法进行模式匹配。

示例

输入

str = "PQRDPQRSSE"; patt = "PQRS";

输出

5

解释

The ‘PQRS’ pattern exists at position 5. So, it prints 5.

输入

str = "PQRDPQRSSE"; patt = "PRQS";

输出

-1

解释

The pattern doesn’t exist in the given string.

输入

str = "WELWELWELCOME"; patt = "WEL";

输出

1, 4, 7

解释

The pattern exists at multiple positions in the given string.

方法

在Zhu-Takaoka算法中,我们将在预处理模式字符串后准备一个ZTBC表。这样,我们就可以知道在发生任何不匹配时,应该将模式移动多少索引才能获得下一个匹配。

让我们逐步了解Zhu-Takaoka算法的工作原理。

首先,我们创建一个26x26维度的ZTBC表。表的每一行和每一列都用大写字母表示。

在第一阶段,所有表元素都等于模式长度,假设在发生任何不匹配时我们需要传递整个模式。

因此,根据“PQRS”模式,表值如下所示。

A  B  C  D  E  F  …
A  4  4  4  4  4  4
B  4  4  4  4  4  4
C  4  4  4  4  4  4
D  4  4  4  4  4  4
..

在此算法中,我们需要将模式的两个字符与字符串从右到左进行匹配。如果我们在模式中找到两个连续匹配的元素,则需要移动模式,使其字符对在字符串和模式中都匹配。

因此,相应地更新ZTBC表。

table [pattern[p-1]][pattern[p]] = len – p - 1 ;

预处理表后,我们需要开始比较字符串和模式。

算法

  • 步骤1 - 在全局范围内定义26x26维度的ZTBCTable[]数组,以存储模式的预处理移动。

  • 步骤2 - 执行prepareZTBCTable()以在预处理模式后填充ZTBCTable()数组。

  • 步骤2.1 - 在prepareZTBCTable()函数中,将所有数组元素初始化为模式长度。

  • 步骤2.2 - 将ZTBCTable[p][patt.charAt(0) - 'A']初始化为模式长度-1,表示单个字符匹配时的移动。

  • 步骤2.3 - 将ZTBCTable[patt.charAt(p - 1) - 'A'][patt.charAt(p) - 'A']更新为模式长度-1-索引。

  • 步骤3 - 接下来,将q初始化为0,并将isPatPresent初始化为false值。

  • 步骤4 - 进行迭代,直到q小于字符串和模式长度的差。

  • 步骤5 - 进行嵌套循环迭代,直到字符串和模式字符从最后开始匹配。

  • 步骤6 - 如果p小于0,则表示我们找到了匹配。因此,打印q作为起始索引,并将isPatPresent更新为true。

  • 步骤7 - 否则,将ZTBCTable[str.charAt(q + patt_len - 2) - 'A'][str.charAt(q + patt_len - 1) - 'A']添加到“q”变量以移动模式。

  • 步骤8 - 最后,如果isPatPresent的值为false,则打印“模式不存在于字符串中”。

示例

Open Compiler
import java.io.*; import java.lang.*; import java.util.*; public class Main { // Declaring custom strings as inputs and patterns public static String str = "PQRDPQRSSE"; public static String patt = "PQRS"; // And their lengths public static int str_len = str.length(); public static int patt_len = patt.length(); public static int[][] ZTBCTable = new int[26][26]; public static void prepareZTBCTable() { int p, q; // Initialize the table for (p = 0; p < 26; ++p) for (q = 0; q < 26; ++q) ZTBCTable[p][q] = patt_len; for (p = 0; p < 26; ++p) ZTBCTable[p][patt.charAt(0) - 'A'] = patt_len - 1; for (p = 1; p < patt_len - 1; ++p) ZTBCTable[patt.charAt(p - 1) - 'A'][patt.charAt(p) - 'A'] = patt_len - 1 - p; } public static void main(String args[]) { int p, q; // Preparing a ZTBC table prepareZTBCTable(); q = 0; boolean isPatPresent = false; while (q <= str_len - patt_len) { p = patt_len - 1; while (p >= 0 && patt.charAt(p) == str.charAt(p + q)) --p; if (p < 0) { // When we get the pattern System.out.println("Pattern exists at index " + (q + 1)); q += patt_len; isPatPresent = true; } else { // Move in the string q += ZTBCTable[str.charAt(q + patt_len - 2) - 'A'][str.charAt(q + patt_len - 1) - 'A']; } } if(!isPatPresent){ System.out.println("Pattern doesn't exists in the given string"); } } }

输出

Pattern exists at index 5

时间复杂度 - O(N*M),其中N是字符串长度,M是模式长度。

空间复杂度 - O(26*26) 用于存储模式移动。

Zhu-Takaoka算法在内存和时间方面效率更高。此外,它将模式的两个字符与字符串进行比较,通过减少比较次数来提高算法的性能。

更新于: 2023年7月4日

149 次浏览

开启你的 职业生涯

通过完成课程获得认证

立即开始
广告