📅  最后修改于: 2023-12-03 14:59:34.277000             🧑  作者: Mango
Boyer Moore算法是一种高效的字符串匹配算法,它采用了两种启发式规则:坏字符规则和好后缀规则。良好的后缀启发式则是利用了好后缀规则来加速匹配过程。
该算法的时间复杂度为 O(mn),其中m和n分别为目标字符串和模式串的长度。但是,在实际应用中,它往往比其他算法(如KMP算法)更快。Boyer Moore算法不仅适用于单模式匹配,还可以用来进行多模式匹配。
坏字符规则是指当匹配失败时,将目标串中最后一个匹配的字符称为坏字符,并查找模式串中是否存在该字符。如果不存在,则将模式串移动到与目标串对齐该字符的位置。如果存在,则移动模式串使得该字符对齐目标串中的坏字符。
以下是坏字符规则的python代码实现:
def bad_character_rule(pattern):
'''
生成坏字符规则下的移动表
'''
table = {}
for i in range(len(pattern)):
table[pattern[i]] = i
return table
好后缀规则是指当匹配失败时,根据模式串中与目标串匹配的子串(称为好后缀),来尽可能地移动模式串。具体地,找到模式串中与目标串匹配的最长后缀子串,然后将模式串移动到与目标串对齐该子串的位置。
以下是好后缀规则的python代码实现:
def good_suffix_rule(pattern):
'''
生成好后缀规则下的移动表
'''
table = {}
size = len(pattern)
# 构造suffix数组
suffix = [-1] * size
for i in range(size):
j = i - 1
while j >= 0 and pattern[suffix[j]+1:i+1] != pattern[j+1:i+1]:
j = suffix[j]
if j >= 0:
suffix[i] = suffix[j] + 1
# 构造gs数组
for i in range(size-1):
j = suffix[i]
if j >= 0:
for k in range(j+1, size):
if pattern[k] in table:
table[pattern[k]] = max(table[pattern[k]], k-j)
else:
table[pattern[k]] = k-j
else:
for k in range(i, size):
if pattern[k] in table:
table[pattern[k]] = max(table[pattern[k]], k-i)
else:
table[pattern[k]] = k-i
# 处理整个模式串匹配的情况
if suffix[size-1] >= 0:
for i in range(size):
if pattern[size-1-i] in table and table[pattern[size-1-i]] == 0:
table[pattern[size-1-i]] = i-suffix[size-1]
return table
良好的后缀启发式是指将坏字符规则和好后缀规则结合起来,找到模式串需要移动的最大距离。具体地,当匹配失败时,它先根据坏字符规则来计算出模式串需要移动的距离,如果可能的话,再根据好后缀规则来调整该距离。
以下是良好的后缀启发式的python代码实现:
def good_suffix_heuristic(text, pattern):
table_bc = bad_character_rule(pattern)
table_gs = good_suffix_rule(pattern)
size_t = len(text)
size_p = len(pattern)
idx_t = size_p - 1
idx_p = size_p - 1
while idx_t < size_t:
if text[idx_t] == pattern[idx_p]:
idx_t -= 1
idx_p -= 1
else:
# 计算坏字符规则下移动的距离
i = table_bc.get(text[idx_t], -1)
j = idx_p - i
# 计算好后缀规则下移动的距离
if j > 0:
gs_length = size_p - j
gs_suffix = pattern[j:]
gs_prefix = pattern[:j]
for k in range(j, size_p):
if gs_prefix == pattern[size_p-k:size_p]:
gs_length = k-j
gs_suffix = pattern[k:size_p]
gs_move = table_gs.get(gs_suffix, size_p) - j
# 取较大值
idx_t += max(gs_move, i)
idx_p = size_p - 1
else:
idx_t += i + 1
idx_p = size_p - 1
# 返回所有匹配结果的起始位置
result = []
while idx_t >= 0:
if text[idx_t+1:idx_t+1+size_p] == pattern:
result.append(idx_t+1)
idx_t -= 1
result.reverse()
return result
text = 'TTATTTGATCCATCTAGCACTTTTTGATTACAGCTGATTAGAGGTTGGCCACATCTCATAGCATGATCCCATCAAAATAG'
pattern = 'GATCCA'
result = good_suffix_heuristic(text, pattern)
print(result) # 输出 [5, 47]
Boyer Moore算法的效率很高,由于其采用了坏字符规则和好后缀规则,可以避免无效的比较,从而减少比较次数。在实际应用中,Boyer Moore算法常常比其他算法(如KMP算法)更快。而良好的后缀启发式则进一步加速了匹配过程,可以更快地找到所有匹配的起始位置。