字符串匹配算法综述
字符串匹配算法综述
对于字符串匹配算法,是在日常学习和工作中最常遇到的问题,字符串匹配算法要求输入主串(string)和子串(pattarn),然后返回子串在主串中第一次出现的位置。进行字符串匹配是学习计算机科学与技术时算法基础的问题,字符串匹配在生活中的应用及其广泛。在如今这个数字化、信息化的时代,字符串匹配算法更是不可或缺的,如我们平时所使用的百度引擎搜索信息时,便是字符串匹配的应用。如今网络迅速发展,如果还想提高运算检索速度,仅通过对硬件的改善提升检索速率是远远不够的,所以,我们必须研发更快、更良好的字符串匹配算法,才能够提升人们在更多领域中对信息处理的速度。根据此,常见的字符串匹配还有: BF(Brute Force,暴力检索)算法,KMP (Knuth-Morris-Pratt算法)算法,BM (Boyer和Moore算法)算法,等等。
1 引言
什么是字符串匹配,字符串匹配的概念:是指一个字符串是否为另一个字符串的子串。我们将短的字符串称为模式串,将长的字符串称为文本串(图1-1):
图 1-1 字符串匹配
字符串A为主串,字符串B是字串,字符串B在字符串A中出现的位置为2,最终返回2。
我们再看另一个例子(图1-2):
图 1-2 字符串匹配示列
在这个例子中,字符串A中并不包含字符串B,因此返回 -1。
基于此,本文利用多个字符串匹配算法,依据时空复杂度(时间复杂度/空间复杂度)O(n),对不同的字符串匹配算法进行分析。
2 BF算法(Brute Force暴力算法)
2.1 BF算法简介
BF(Brute Force,暴力检索)算法是最直接的暴力匹配。暴力算法的主要思路是从主串第一个字符位置出发并与字串进行匹配,然后假设主串的第一个字符位置与子串的第一个字符位置一致,那么继续比较后续字符。若前二个字符都不相同,则子串由主串的第二个字符起,以此类推。相等则继续匹配,不相等则子串之间又再次进行匹配,直至子串之间全部匹配成功,若主串中含有子串,则匹配成功,若不含有子串,则匹配失败。
2.2 Brute Force暴力算法的基本原理
首先,从主串的第一位开始,把主串和子串的每个字符一一比较(图2-1):
图 2-1 BF算法一一比较
主串和子串的第一个字符明显不匹配,因此,从第二个字符开始比对(图2-2):
图2-2 BF算法匹配字符
二者匹配,继续比较(图2-3):
图2-3 BF算法再次匹配字符
主串的第三个字符位置两个字符不匹配,因此,将子串整体往后移一位,从主串的第三个字符串开始比较(图2-4):
图2-4 BF算法匹配字符后移
主串的第三个字符是b,子串的第三个字符也是b,两者相等,继续比较(图2-5):
图2-5 BF算法匹配字符比较[1]
主串的第四个字符是c,子串的第二个字符也是c,两者相等,继续比较(图2-6):
图2-6 BF算法匹配字符比较[2]
主串的第五个字符是e,子串的第五个字符也是e,两个字符串一样,字符串匹配完成,主串包含子串,子串在主串中出现的位置是2,返回2(图2-7):
图2-7 BF算法返回子串位置
2.3 利用python实现BF算法:
def BF(s, p):
"""
BF算法字符串匹配
"""
indies = []
n = len(s)
m = len(p)
for i in range(n - m + 1):
index = i
for j in range(m):
if s[index] == p[j]:
index += 1
else:
break
if index - i == m:
indies.append(i)
return indies
2.4 BF算法总结:
BF(Brute Force,暴力检索)算法是初学者最容易理解的算法,也是传说中的暴力检索算法,假设主串和子串的长度分别为A,B,则它时间复杂度很容易达到O(A*B)。时间复杂度较大。虽然时间复杂度较高,但很容易理解,很适合初学者进行学习。有时候它的时间复杂度也能达到O(A+B),所以,此算法依旧被大量使用。
3 KMP算法(Knuth-Morris-Pratt算法)
3.1 KMP算法简介
Knuth-Morris-Pratt算法是一种比较高效的字符串匹配算法,它也是找到子串出现在主串中第一次出现的位置。比如: mnmnmnp,那么nmn在其位置1处(字符串从0开始计数),np在其位置5处,我们第一时间想到的是暴力匹配,即BF算法。但利用BF算法会导致时间复杂度为O(m*n),而KMP算法保证了时间复杂度为O(m+n)。
3.2 KMP算法的基本原理:
KMP算法是一种字符串匹配算法,它是对朴素模式算法(暴力匹配)的改进。 我们先看朴素模式下是怎么进行字符串匹配的。假设我们有两个字符串,被匹配的大串称为 主串,要匹配的小串称为模式串(图3-1):
图3-1 KMP算法基本原理
发现x与c不同后,进行移动(图3-2):
图3-2 KMP算法开始匹配
a与x不同,再次移动(图3-3):
图3-3 KMP算法匹配判断
此时比较到了c与y,于是下一步移动成了下面这样(图3-4):
图3-4 KMP算法匹配结果
这次移动和前二次移动有什么差别呢这一次的移动和前二次的移动有所不同,前二次移动时,直接把子串的首字符和前一次主串比对在不同的位置对齐,而这次不是,原因是在这次移动前,y和c已经对齐,而y之前的ab又和子串的前缀ab相同,所以ab不需重新比较,而是直接在第三个位置进行比较(图3-5):
图3-5 KMP算法再次匹配
Kmp对于这种情况就直接使用当前所比较的字符串前面的最长相同前后缀。再将前缀与主串对齐,然后再比较后面的字符串的字符。这里,就到了KMP的核心思想了,如何确定子串中每个字符之前的最长相同前后缀(图3-6):
图3-6 KMP算法确定前后缀
在主串的每个字符下记录一个数字用来记录以这个字符结尾的最长前后缀相同子串长度。开始都记录为0,并且第一个字符确定为0,开始比对(图3-7):
图3-7 KMP算法进行对比
A与b和c都不同,所以b和c下数字都为0,a和a对齐(图3-8):
图3-8 KMP算法对比结果
此此时a与a相同,所以a底下的数值为1,也就是说比对相同的第一个字符下为1,b和b相同,因此b底下的数值为2,而c和a不同,此时上边的文字串不动,下边的文字串移动到当前比对地址即c的前一个的下方的数值的地方(图3-9):
图3-9 KMP算法规则位移
对于主串来说c的前一位是b,且下方所对应的数字为0,所以将子串的第0位与之前比对不匹配的位置对齐,即(图3-10):
图3-10 KMP算法再次匹配
子串位置如图所示,继续进行比对,比对到c与a时,发现主串与子串字符不匹配(图3-11):
图3-11 KMP算法出现不匹配
这时候,c和a不匹配,则比较子串所对应位置主串字符下的数字的位置(图3-12):
图3-12 KMP算法比较数字位置
也就是位置为2的地方与上面比对位置对齐(图3-13):
图3-13 KMP算法位置对齐
此时c与c相同,整个字符串自比对完成(图3-14):
图3-14 KMP算法自对比完成
如果匹配不成功,则对比主串前一字符下的数字的位置,这么做是为了要找到前一个字符位置下相同前缀中的最长相同前缀,比如刚才的例子(图3-15):
图3-15 KMP算法查找前缀
此时a前边是“abcab“,所以要找到”abcab“的最长相同前缀,就是ab(图3-16):
图3-16 KMP算法查找成功
然后再移动到ab与ab对其的位置继续比较即可。
3.3 利用python实现KMP算法,如下:
def compute_prefix_function(p):
m = len(p)
pi = [0] * m
k = 0
for q in range(1, m):
while k > 0 and p[k] != p[q]:
k = pi[k - 1]
if p[k] == p[q]:
k = k + 1
pi[q] = k
return pi
def kmp_matcher(t, p):
n = len(t)
m = len(p)
pi = compute_prefix_function(p)
q = 0
for i in range(n):
while q > 0 and p[q] != t[i]:
q = pi[q - 1]
if p[q] == t[i]:
q = q + 1
if q == m:
return i - m + 1
return -1
3.4 KMP算法总结
总的来说,就是找到子串中的每个字符的最长相同前后缀,如果子串的长度为a,那么主串的指向是一直向前移动,子串的指向也是向前的,所以最后的结果是长度为2a,时间复杂度则为O(a),KMP算法中运用了最长相同前后缀的方法进行比对,如果子串的长度为b,则KMP算法的时间复杂度为O(a+b),提高了算法效率。
4 BM算法(Boyer和Moore算法)
4.1 BM算法简介
BM (Boyer和Moore算法) 算法的执行效率较高,而且比较容易理解。常用一些软件中的快捷查找方法都是利用此算法。
4.2 BM算法的基本原理
我们用例子来了解BM算法的基本原理(图4-1):
图4-1 BM算法基本原理
第一步,将两个字符串左端对齐,从右端开始比对。S和E,通过此,便可以发现字符串不匹配。因此,我们便需要寻找一下子串中是否包含这个字符s,发现子串中并没有s,这时我们便需要将子串移动到主串s所对应的下一个位置(图4-2):
图4-2 BM算法移动子串位置
然后我们再次从字符串的尾部开始比对,发现子串尾部位置p和E不匹配,在子串中看是否存在p,子串中包含p,因此,便将主串和子串中p的位置对齐(图4-3):
图4-3 BM算法主、子串对齐
继续从尾部进行比较,发现E匹配,L匹配,P匹配,M匹配,但I和A不匹配,再次寻找子串中是否有I,此时发现主串中的E可以和子串中的第一个字符E对应,可直接将子串移动到两个E对应的位置 (图4-4):
图4-4 BM算法字符匹配
然后继续从尾部开始比对,P和E不匹配,则看子串中是否包含P,存在,则移动子串的P和主串的P对应的位置对齐(图4-5):
图4-5 BM算法字符匹配对齐
再继续从尾部开始以一比对,匹配成功。
4.3 利用python实现BM算法:
def getBMBC(pattern):
#预生成坏字符表
BMBC = dict()
for i in range(len(pattern) - 1):
char = pattern[i]
#记录坏字符最右位置 (不包括模式串最右侧字符)
BMBC[char] = i + 1
return BMBC
def getBMGS(pattern):
#预生成好后缀表
BMGS = dict()
#无后缀仅限根据坏字移位符规则
BMGS[''] = 0
for i in range(len(pattern)):
#好后缀
GS = pattern[len(pattern) - i - 1:]
for j in range(len(pattern) - i + 1):
#匹配部分
NGS = pattern[j:j + i + 1]
#记录模式串中好后缀最靠右位置(除结果处)
if GS == NGS:
BMGS[GS] = len(pattern) - j - i - 1
return BMGS
def BM(string, pattern):
"""
Boyer-Moore算法实现字符串查找
"""
m = len(pattern)
n = len(string)
i = 0
j = m
indies = []
BMBC = getBMBC(pattern=pattern)
#坏后缀
BMGS = getBMGS(pattern=pattern)
#好后缀
while i < n:
while(j > 0):
if i +j -1 >= n:
#当无法继续向下搜索就返回值
return indies
#主串判断匹配部分
a = string[i +j - 1:i + m]
#模式串判断匹配部分
b = pattern[j - 1:]
#当前位匹配成功则继续匹配
if a == b:
j = j - 1
#当前位匹配失败根据规则位移
else:
i = i + max(BMGS.setdefault(b[1:],m),
j - BMBC.setdefault(string[i + j - 1], 0))
j = m
#匹配成功返回匹配位置
if j == 0:
indies.append(i)
i += 1
j = len(pattern)
4.4 BM算法总结:
BM (Boyer和Moore算法) 算法容易理解,且执行小路较高,是一种构思比较精巧的字符串匹配算法。BM算法与暴力算法和KMP算法不同,BM算法采用后缀比对法,其核心思想在于,通过坏字符算法和好后缀算法,找到子串每次后移的最大距离。BM算法开始将主串与子串头对齐,尾比对,如果尾部不同,则可一次确定比对失败,将子串进行位移。
5 总结
BF(Brute Force,暴力检索)算法是初学者最容易理解的算法,也是传说中的暴力检索算法,时间复杂度较大。虽然时间复杂度较高,但很容易理解,很适合初学者进行学习。有时候它的时间复杂度也能达到O(A+B),所以,此算法依旧被大量使用。
kmp算法中,找到子串中的每个字符的最长相同前后缀, KMP算法中运用了最长相同前后缀的方法进行比对,如果主串的长度为a,子串的长度为b,则KMP算法的时间复杂度可记为为O(a+b),相对于暴力法,提高了算法效率。
BM算法采用后缀比对法,其核心思想在于,通过坏字符算法和好后缀算法,找到子串每次后移的最大距离。BM算法开始将主串与子串头对齐,尾比对,如果尾部不同,则可一次确定比对失败,将子串进行位移。
__EOF__

本文链接:https://www.cnblogs.com/Hollahpain/p/17037846.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix