【算法】KMP算法模板

#include<bits/stdc++.h>
using namespace std;
/*
abcabcde中开始len指向a,j指向b 
a[j]!=a[len],且len无路可退
让Next[j] = len = 0,同时j++指向c

其他的同理,当j指向3(也就是第二个a时)
a[j] == a[len](此时j=3,len=0)
让Next[j] = ++len后j++(此时j=4,len=1,Next[j]==1)
j再指向4,也就是第二个b,此时len=1;
a[j] = a[len]
同理Next[j] == 2
...
当j == 6时,a[j] = d,a[len] = a(len==3)
两者不相等
len = Next[len-1] == Next[2] ==0
再进行循环判断 

 
更新完成后Next数组为
a	b	c	a	b	c	d	e
0	0	0	1	2	3	0	0	 
*/ 
void KMP(string a,int n,int Next[]){    //a是待求子串,n是待求子串的长度,Next数组
    int len=0;
    int j=1;
    Next[0]=0;
    while(j<n){
        if(a[j]==a[len]){    
            /*当两者相等时,说明j的位置和前面对应前缀的位置相等,
            所以先让len的长度加1,再让j的长度加1*/
             Next[j++]=++len;
        }
        else{
            /*当对应位置不相等时,当len>0(说明len还有路可退)
            让len返回他上一个位置的next数组的值
            
            当对应位置不相等,且len==0(len无路可退),直接让Next[j]=len再让j++*/
            if(len>0){
                len=Next[len-1];
            }
            else{
                Next[j]=len;
                j++;
            }
        }
    }
    /*上面求得是每一位的最大前缀和,Next数组是代表前一位的,
    所以用for循环遍历,将所有位置后移,再让Next[0]=-1*/
    for(int i=n-1;i>0;i--){
        Next[i]=Next[i-1];
    }
    Next[0]=-1;
}
int main(){
    int Next[100]={0};
    string b="abcdefabcdeabcabcdefg";
    string a="abcabcde";
	int n=a.length();
	KMP(a,n,Next);    //求Next数组
	int m=b.length();
	int i=0;
	int j=0;
	while(i<n&&j<m){    //当两个字符串任意一个走到头了,就跳出循环
		if(i==-1||a[i]==b[j]){        //注意不要忘了i==-1的条件
			i++;
			j++;
		}
		else{
			i=Next[i];
		}
	}
	if(i==n){
		cout<<j-i;        //输出比对到的第一个数的下标,有些题下标是从1开始,这里就需要加1
	}
	else{
		cout<<"-1";       //没找到输出-1
	}
}

注意事项:

1.Next数组首字母要大写,否则在Devc++里会有定义冲突

2.KMP函数里最后遍历的范围是下标为字符串长度减一的位置到下标为1的位置,不是下标到零的位置,实际循环长度是n-1不是n

3.遍历是i--不是i++,注意不要笔误

4.主函数查找过程中不要忘记i==-1的情况,如果等于负一直接让i和j同时++,避免陷入死循环

5.有些题目的数组是从下标为1的位置开始,最后输出i-j+1(匹配成功后第一个下标的位置),从零开始就是i-j

6.判断语句不要直接用字符串长度直接判断(如n<a.length())这样可能会造成n小于0时循环无法正常进行,应该先让一个变量等于a.length(),再让这个变量和n比较

if(n<a.length())
    n++;        //有可能当n小于0时发生错误,跳出循环

//应写成
int m=a.length();
if(n<m)
    n++;

当时间限制比较紧的题目中也可以直接删除KMP函数中的遍历后移部分

for(int i=n-1;i>0;i--){
   Next[i]=Next[i-1]
}
Next[0]=-1;        //这一部分

然后再后面的查找过程中加上几句判断语句

if(i>0)
	i=Next[i-1];
else
    i=-1;

也可以时间目的,并且用时更短

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值