KMP算法

思路:

BF(朴素模式匹配)​

朴素的模式匹配算法:

KMP算法:

next数组:

 优化

 代码实现:


考研不要求写代码但要会手算next[j]以及知道nextval[ ]优化方法

思路:

BF(朴素模式匹配)

 

朴素的模式匹配算法:

直接进行搜索匹配。基本思想是:从主串S的第一个字符开始和模式T的第一个字符进行比较,若相等,则继续比较两者的后续字符;否则,从主串S的第二个字符开始和模式T的第一个字符进行比较。重复上述过程,若T中的字符全部比较完毕,则说明本趟匹配成功;否则匹配失败。


KMP算法:

主串指针不回退,每次匹配失败时只回退模式串的指针

next数组来标记模式串回退的位置,当发现字符不匹配时,模式串指针(j)回溯到j=next[j]

特殊情况当j=next【j】=0时该怎么办?

next数组:

怎么求?

一文解决如何计算next[ ]_Myblog-CSDN博客

next[ j ]=由下标为1~j-1的字符组成的字符串最长的相等前后缀长度+1

例如下图中j=6,next[6]怎么求?

先将下标1~5的字符取出来构成字符串a b a b a

最长的前后缀相等字符串为 a b a ->next [6]=3+1=4;

特别的:next【1】=0和next【2】=1是固定的

 

 代码实现:

//这里传入的字符串为"#abc....."
void get_next(string t, vector<int> &next) {//只和模式串(字串)有关系
	int i = 1, j = 0;
	next[1] = 0;
	int tlen = t.length() - 1;
	while (i < tlen)
	{
		if (j == 0 || t[i] == t[j]) {
			++i;
			++j;
			next[i] = j;
		}
		else {
			j = next[j];
		}
	}
}

 优化

以下动图演示了使用next【j】原理导致出现重复操作的情况

 

 这种情况下我们可以使用nextval【j】数组进行优化:

 代码实现:

#include <iostream>
#include <vector>
#include <string>
using namespace std;
//BF模式匹配
int index(string s, string t, int pos) {
	s = '#' + s, t = '#' + t;
	int j = 1;
	int i = pos;
	int slen = s.length() - 1;
	int tlen = t.length() - 1;
	while (i <= slen && j <= tlen)
	{
		if (s[i] == t[j]) {
			++i;
			++j;
		}
		else {
			i = i - j + 2;
			j = 1;
		}
	}
	if (j > tlen)return i - tlen;
	else return 0;
}
//这里传入的字符串为"#abc....."
void get_next(string t, vector<int> &next) {//只和模式串(字串)有关系
	int i = 1, j = 0;
	next[1] = 0;
	int tlen = t.length() - 1;
	while (i < tlen)
	{
		if (j == 0 || t[i] == t[j]) {
			++i;
			++j;
			next[i] = j;
		}
		else {
			j = next[j];
		}
	}
}
//这里传入的s,t是最长输入的字符串
int index_kmp(string s, string t, int pos) {
	//为了下标表示方便,我们需要在字符串加上一个"#",这里加什么都行,目的只是为了字符串下标从1开始
	s = '#' + s, t = '#' + t;
    //从头开始,取i=1
	int j = 1; int i = pos;
	//next[ ]数组的长度=t.length()
	vector<int >next(t.length());
	get_next(t, next);
	//slen的长度就是没加"#"前的长度
	int slen = s.length() - 1;
	int tlen = t.length() - 1;
	while (i <= slen && j <= tlen)
	{
		if (s[i] == t[j] || j == 0) {
			++i;
			++j;
		}
		else {
			j = next[j];
		}
	}
    //下标从1开始,假如下标从0开始对应i-tlen-1
	if (j > tlen) return i - tlen;
	else return -1;
}
int main()
{
	string s;
	string t;
	int pos;
	//输入不需要在前面加"#"。
	cout << "请输入主串:";
	cin >> s;
	cout << "请输入子串:";
	cin >> t;
	cout << "请输入搜索起始位置:";
	cin >> pos;
	//cout << "BF模式匹配:" << index(s, t, pos) << endl;
	cout << "KMP模式匹配:" << index_kmp(s, t, pos) << endl;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值