KMP算法挖坑

前言

目前是写给自己看的,,仅供参考

左神的KMP代码 

#include<iostream>
#include<string>
using namespace std;
int* getNextArray(string str2){
	if(str2.size() == 1){
		int* next = new int[1];
		next[0] = -1;
		return next;
	}
	int* next = new int[str2.size()];
	next[0] = -1;
	next[1] = 0;
	int i = 2;
	// int cn = 0;
	int cn = next[i-1];//被比较对象的下标位置
	while(i < str2.size()){
		if(str2[i-1] == str2[cn]){
			next[i++] = ++cn;
		}else if(cn > 0){
			cn = next[cn];
		}else{
			next[i++] = 0;
		}
	}
	//退出循环意味着数组已经填完了,
	return next;
}
int getIndexOf(string str1, string str2){
	if(str1.size() == 0 || str2.size() == 0)
		return -1;
	int i1 = 0;
	int i2 = 0;
	int* next = getNextArray(str2);
	while(i1 < str1.size() && i2 < str2.size()){
		if(str1[i1] == str2[i2]){
			i1++;
			i2++;
		}else{
			//当i2已经到了next的0位置,此时next【0】 值为-1,so 不用显示的指定i2=0了;
			if(next[i2] == -1){
				i1++;  
			}else{
				i2 = next[i1];
			}
		}
	}
	return i2==str2.size()? i1-i2:-1;
}
 
int main(){
	cout << getIndexOf("abcabcd","cab");
	return 0;
}

以上两个函数,一个是求解next函数,一个是使用next函数

getIndexOf()函数

利用现成的next数组来判断,有以下情况(i和j代替代码中的i1和i2)

首先i指向string,j指向pattern,string[i]和pattern[j]如果相等则两个都加一,很直观;

如果string[i]和pattern[j]不等,则把j指针跳到前面的next[i]位置,如果j指向的是第一个pattern字母,即next[j]==-1,则i直接加一就好了,

 

next数组的求解

next数组长度是和pattern一样的,含义是:数组里每位i代表着0到i-1的串的最长匹配前后缀(这词用的可能不准确,看例子理解),

首先人为规定第0位为-1,第一位为0,第二位开始计算,代码也是很精简的,两种情况:

cn是上一个字符串的最长前缀的最后一位的索引,同时也代表着最长前缀长度

1. 如果cn指向的值等于当前的下一位,则下一位的next值是现在的长度+1,这个好理解

2.如果cn的值不等于当前的下一位,则下一位的next值是next[cn],也就是最长前缀的最后一位,它对应的最长前缀,为什么呢,这个证明就没那么直观了,以后再弄TODO

TODO上面这些有点瑕疵,以后再来修改2020-5-5,
---

代码写起来很简单,记住这几种情况就好,特别是cn>0的情况,让cn=next[cn]比较难理解要记住

============

知乎有人说网上KMP的实现又很多种,眼花缭乱的,轮子哥推荐了一本<柔性字符串匹配>,评论说"单拿KMP算法来讲,这是我见过的讲解最清晰明了的书了!",设为TODO,以后有空看吧...而这篇的代码是从左神课里选的

KMP的算法复杂度

目前没找到证明,但是网上说是O(M+N),算法第四版里只写了运算次数

推荐阅读:

如何更好地理解和掌握 KMP 算法? - 海纳的回答 - 知乎 https://www.zhihu.com/question/21923021/answer/281346746

参考:

  1. https://blog.csdn.net/a3765421/article/details/88863859
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值