字符串的模式匹配

字符串的模式匹配描述:在字符串T中查找是否有跟另一字符串pat相等的子串。

朴素的模式匹配-----BF算法:利用pat中的字符依次与T中字符依次比较

int Find(string T, string pat, int k){
	//在T中从K个字符开始寻找模式串pat在串中的位置,找不到返回-1,找到返回第一次匹配的位置
	int i, j;
	for(i = k; i <= T.size() - pat.size(); ++i){
		for(j = 0; j < pat.size(); ++i){
			if(T[i+j] != pat[j]){
				break;
			}
		}
		if(j == pat.size()){
			return i;
		}
	}
	return -1;
}

这个算法是一种带回溯的算法,一旦比较不等,就将模式pat右移一位,再从p0开始进行比较。若T的长度为n,pat的长度为m,算法的运行时间为O(n×m)

改进的匹配算法-----KMP算法

改进:避免朴素模式匹配中的回溯操作
前缀:只包含首字母、不包含尾字母的所有子串。
后缀:只包含尾字母、不包含首字母的所有子串。

若现在有一字符串aabaaf,求其前缀表:
a -> 0
aa -> 1
aab -> 0
aaba -> 1
aabaa -> 2
aabaaf -> 0

字符串:a a b a a f
前缀表:0 1 0 1 2 0

代表当某位失效时,需要跳到下标为前一字符对应的相等最长前缀长度的位置,如在字符f位置失配,则需要找到字符f前一位字符a对应的前缀表中的数值2,接着跳到下标为2的位置继续下一次匹配。

前缀表有三种表示方式:
1、直接存储: 0 1 0 1 2 0
2、减一后存储: -1 0 -1 0 1 -1
3、添加首位值-1,将前缀表右移一位: -1 0 1 0 1 2 --------------此时字符对应前缀表中的数值,就是该字符失配时需要跳到的位置

前缀表的计算方式

1、计算直接存储方式的前缀表
①初始化
②前缀不相同的处理
③前缀相同的处理
④更新next数组

void getNext(string pat, int next[]){
	//i指向后缀末尾位置,j指向前缀末尾位置,同时j还代表i之前包括i的子串的最长相等前后缀长度

	//1、初始化
	int i, j = 0;
	next[0] = 0;
	
	for(i = 1; i < pat.size(); ++i){
		//2、前缀末尾、后缀末尾不匹配时,j进行回退,j到0时,不用回退,故j > 0
		while(j > 0 && s[i] != s[j]){
			j = next[j - 1];
		}

		//3、前后缀末尾相同的情况
		if(s[i] == s[j]){
			j++;
		}

		//4、更新next数组
		next[i] = j;
	}
	

}

2、添加首位值-1,将前缀表右移一位

void getNext(string pat, int next[]){
	int j = 0, k = -1;
	int lengthPat = pat.size();
	next[0] = -1;
	
	//计算next[j]
	while(j < lengthPat){
		if(k == -1 || pat[j] == pat[k]){
			j++;
			k++;
			next[j] = k;
		}
		else{
			k = next[k];
		}
	}
}

右移一位的next数组的KMP算法实现快速匹配

一般地,若设在进行某一趟匹配比较时在模式pat的第j位失配,如果j>0,那么在下一趟比较时模式串pat的起始比较位置是next(j),目标串T的指针不回溯,仍指向上一趟失配的字符;如果j=0,则目标串T进一,模式串pat回到起始0的位置,继续进行下一次比较。

int fastFind(string T, string pat, int k, int next[])const{
	//用模式串pat在目标串T中从k的位置开始寻找,找到则返回pat在T中开始的下标,否则返回-1
	int posP = 0;       //两个串的扫描指针
	int posT = k;
	int lengthP = pat.size();          //模式与目标串的长度
	int lengthT = T.size();
	while(posP < lengthP && posT < lengthT){
		if(posP == -1 || pat[posP] == pat[posT]){
			posP++;
			psoT++;
		}
		else{
			posP = next[posP];
		}
	}
	if(posP < lengthP){
		return -1;
	}
	else{
		return posT-lengthP;
	}
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值