数据结构与算法详解——字符串匹配算法篇(附c++实现代码)

本文详细介绍了三种字符串匹配算法:BF(Brute Force)算法,RK(Rabin-Karp)算法和KMP算法。BF算法简单但效率较低,时间复杂度为O(n*m)。RK算法利用哈希函数提高效率,时间复杂度为O(n)。KMP算法通过预处理避免回溯,时间复杂度为O(m+n)。文章提供了算法原理及C++实现代码。
摘要由CSDN通过智能技术生成


  字符串匹配就是在主串A中查找模式串B,例如在主串abababc中查找模式串abc是否存在,记主串A的长度为n,模式串B的长度为m,n>=m。

BF算法

  BF(Brute Force)算法,又叫暴力匹配算法或者朴素匹配算法,思路很简单:在主串中取前下标为[0,m-1]这m个字符的子串和模式串逐个字符逐个字符比较,如果完全一样就结束并返回下标;如果有不一样的,那么主串中的子串后移一位,主串中[1,m]这个子串和模式串继续比较,… ,主串中[n-m,n-1]这个子串和模式串继续比较。
  主串中长度为m的子串有n-m+1个。

主串 a b a b a b c
模式串 a b c
主串 a b a b a b c
模式串 a b c
主串 a b a b a b c
模式串 a b c
主串 a b a b a b c
模式串 a b c
主串 a b a b a b c
模式串 a b c
int BF(std::string &s,std::string &pattern) {
   
	int n = s.length(), m = pattern.length();
	for (int i = 0; i < n-m+1; i++) {
   
		int j = 0;
		for (; j < m; j++) {
   
			if (s[i + j] != pattern[j])
				break;
		}
		if(j==m)
			return i;	//匹配到了,返回主串中的下标
	}
	return -1;	//匹配不到
}

  最坏的情况下,在第一个for循环里,i 从0到n-m走满共n-m+1次,第二个for循环里,j 从0到m-1走满共m次,因此最坏的情况下时间复杂度为O(n*m),举个例子,在bbbbbbf中查找bf,所有n-m+1个子串都要走完,并且每次和模式串比较都要比较m次,总共比较n-m+1次。
  BF算法最大的优点就是简单,代码不容易出错,在主串和模式串的长度都不大的时候还是比较实用的。

RK算法

  RK(Rabin-Karp)算法,是用两个发明者的名字命名的。思路也比较简单:对主串中n-m+1个子串求哈希值,模式串也求哈希值,然后比较子串的哈希值和模式串的哈希值,如果不相等证明不匹配,如果相等就匹配(在没有哈希冲突的情况,冲突的情况后面会讲)。
  这个算法对哈希函数的设计要求会高一点,当然最好就不存在哈希冲突,就会比较简单,相等就匹配,不相等就不匹配。
  来看看这样一个设计:假设主串和模式串只有a-j这10个字母,我们可以直接将字符串映射成整数(a-j对应十进制0-9),例如bcd我们可以直接映射成bcd=1*10*10+2*10+3=123,这样就不存在哈希冲突了。那如果现在是a-z这26个字母,我们可以用同样的思路,但是使用26进制,a-z对应0-25:例如bcd=1*26*26+2*26+3=731。
  这个哈希函数是有规律的,当前子串的哈希值hash[i]是可以根据上一个子串的哈希值hash[i-1]计算得到,来看看下面这个例子:
在这里插入图片描述

  上面的子串aba的起始坐标为i-1,哈希值为hash[i-1],下面子串bab的起始坐标为i,哈希值为hash[i],我们知道两个子串中都有ba,但是下面的ba映射成的值要比上面的ba要大26倍,因为所在的位置不一样,下面的ba在最高位和第二位,下面的ba在第二位和第三位,那么我们将hash[i-1]乘26,上下子串ba的hash值都相同了,然后再减去上面子串的最高位a(注意此时的a也是乘多了个26的),最后加上下面子串的末尾的b即可。最终的计算结果就同上图中的计算一样,注意蓝色框框的m即可,是m而不是m-1,因为hash[i-1]乘了26。

//假设哈希值不会溢出int的范围
int RK(std::string& s, std::string& pattern) {
   
	int n = s.length(), m = pattern.length();
	int p = pow(26, m);	//26的m次方

	int* hash = new int[n - m + 1];
	hash[0] 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值