模式匹配(BF算法和KMP算法)

此算法的作用是查找给定子串在母串中的位置

BF算法

一种简单但效率不高的算法

int BF(string s, string t)
{
	int i = 0;
	int j = 0;
	int lens = s.length();
	int lent = t.length();
	while (i < lens && j < lent)
	{
		if (s[i] == t[j])
		{
			i++;
			j++;
		}
		else
		{
			i = i - j + 1;
			j = 0;
		}
	}
	if (t[j] == 0)
	{
		return i - j + 1;
	}
	else
	{
		return 0;
	}
}

总体思路是如果子串和母串的其中一个字符匹配,就继续匹配下一个字符,如果遇到不相同的,则子串的下标回到最开始的位置,母串的下标也回溯,直到某一个串的下标到最后了。就进行判断,如果是子串到最后了,说明子串全部匹配成功,则返回第一个字符的下标。反之如果是母串到最后了,就说明子串没匹配完,匹配失败,返回0。

注意我这里的位置是从1开始的所以子串不在母串中返回0。

因为匹配失败时,两个下标都要回溯,导致效率低下,那么能不能减少回溯的次数或程度呢?

答案显然是可以的,就是KMP算法。

KMP算法

我先放代码

int KMP(string s, string t)
{
	int i = 0;
	int j = 0;
	int lens = s.length();
	int lent = t.length();
	int next[10000] = { 0 };                ///
	Find_Next(t, next);						///
	while (i < lens && j < lent)
	{
		if (j == -1 || s[i] == t[j])		///
		{
			i++;
			j++;
		}
		else
		{
			j = next[j];					///
		}
	}
	if (t[j] == 0)
	{
		return i - j + 1;
	}
	else
	{
		return 0;
	}
}

大体上和BF差不多,有不同的地方我在后面加了一些斜杠。

我先提一个细节:为什么要搞一个int变量装串的长度呢,不用行不行呢?现实是不行!因为string的求长度函数的返回值是无符号int,而 j 有可能 为-1,两者比较会出错。

KMP的思路和BF差不多,只是回溯的时候只回溯 j,i 不动,为啥可以这样呢?

假设有

这样一个子串DABCDABD

这样一个母串DABCDABCDABD

在进行匹配时,前面都很顺利就是最后一个字母不对如果是BF算法,那就会全部回溯到最开始的时候,但这样很费时间,我们仔细观察子串和母串的规律

DABCDABD

DABCDABCDABD

这两个蓝色片段是相同的,那我可不可以 i 保持不动,j 回溯到紫色c的位置然后继续匹配呢,实际上这样节约了时间,而且这种情况不是巧合,回溯到哪里是可以预知的,具体就是 j 回溯到next(j)的位置,可以看看上面的代码。

现在想想这么知道有哪些片段相同呢。

在一开始的时候

DABCDABD

DABCDABCDABD

当 i 指向最后一个D和 j 指向红色C时,前面的绿色片段是相同的 那我只要保证子串中蓝色的DAB和绿色的DAB相同,就可以保证母串中绿色DAB,和子串中蓝色DAB相同了(a=b,b=c, 所以a=c)。

所以next数组的数据是说明在 j 位置时,子串前面最大有多少字母相同。(这里规定 j=0时,next(j)=-1)

给一些例子帮助理解

请输入模式串:A B C D A B C

next数组为:   -1 0  0  0 0 1  2

在第二个B时前面的A和后面A相同。

第二个C时前面的AB和C后面的AB相同。

请输入模式串:A  A  A  A  A  A B

next数组为:   -1  0  1  2  3  4  5

请输入模式串:A B A C D A B A B C

next数组为:   -1 0  0 1 0  0 1 2 3  2

所以Find_next函数就是建立一个这样的next数组。

这里也附上代码

void Find_Next(string s, int next[])
{
	int max = s.length();
	int i = 0;
	int j = -1;
	next[0] = -1;
	while (i <= max)
	{
		if (j == -1 || s[i] == s[j])
		{
			i++;
			j++;
			next[i] = j;
		}
		else
		{
			j = next[j];
		}
	}
}

跟KMP算法竟然长得差不多。

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值