KMP算法

背景&暴力搜索法略

看了好多文章和视频和书,这个视频属于帮我捅破一层窗户纸的那个。https://www.bilibili.com/video/av11866460

输入:主字符串s,模式字符串p。
输出:在s中,p第一次出现的位置或-1。

最长公共前后缀序列

这个概念有点拗口,拆开来看:

  • 对于模式字符串p,如果存在一个真子串str,str既是p的前缀,又是p的后缀,则str是p的公共前后缀。如:aacdaa的公共前后缀既可以是a,也可以是aa;注意aa的公共前后缀只有a而不包括aa。
  • p的所有公共前后缀中,最长的那个子串就叫最长公共前后缀。比如:aacdaa的最长公共前后缀就是aa,而abcdhjhjabcd的公共前后缀只有abcd,所以最长公共前后缀也只有abcd。
  • 对于p的每个元素p[i],令v[i]表示p[0]~p[i-1]的最长公共前后缀的长度,令v[0]为-1;则能得到最长公共前后缀序列。比如ababc的最长公共前后缀序列c就是[-1,0,0,1,2]。显然v[1]必然是0。

代码如下:

vector<int> common(string s) {
	vector<int> v;
	v.push_back(-1);
	for (int i = 1;i < s.size();i++) {
		for (int j = i - 1;j >= 0;j--) {
			if (s.substr(0, j) == s.substr(i - j, j)) {
				v.push_back(j);
				break;
			}
			else if (j == 0)v.push_back(0);
		}
	}
	return v;
}

注:《算法第四版》中把这一过程抽象成一个状态机,这也是可以理解的

移动

移动的过程就很容易了,主串t和模式串p从i=0开始扫,遇到不匹配的就将模式串的指针调整至最长公共前后缀序列的索引i处——next[i]。直至最后。

int kmp(string pattern, string target) {
	vector<int> next = common(pattern);
    int posP = 0, posT = 0;
    int lengthP = pattern.size();
    int lengthT = target.size(); 
    while (posP < lengthP && posT < lengthT) {				//对两串扫描 
        if (posP == -1 || pattern[posP] == target[posT]) {	//对应字符匹配 
            posP++;
			posT++;
		}
		else posP = next[posP];								//失配时,用next数组值选择下一次匹配的位置 
	}
    if (posP < lengthP) return -1;							//匹配失败
    else return posT - lengthP;								//匹配成功 
}
测试shell
int main()
{
	string pattern = "ababc";
	string target = "duababeababc";
	cout << kmp(pattern, target);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值