【算法】KMP 字符匹配

字符串匹配

主要参考:

http://www.ruanyifeng.com/blog/2013/05/Knuth–Morris–Pratt_algorithm.html
理解KMP 的9张PPT:http://weibo.com/1580904460/BeCCYrKz3#_rnd1405957424876
https://www.cnblogs.com/ZuoAndFutureGirl/p/9028287.html

在这里插入图片描述

假设模式串为P,原串为S

1 朴素方法

最坏时间复杂度:O(P.length*S.length)

2 KMP

时间复杂度:O(P.length+S.length)
KMP算法步骤:
1.构造next数组
2.将模式串和原串进行匹配

3 KMP相关练习

3道都是模板题,大差不差,主要在于巩固,加深记忆。
算法练习1 #1015 : KMP算法
http://hihocoder.com/problemset/problem/1015

#include <iostream>
#include <cstring>
using namespace std;
#define MAXN 10005
int next1[MAXN];
//得到next1数组 next1[j]表示字符子串(0~j)中前缀后缀相等的最长字符个数(-1表示0个字符相等,0表示有1个字符相等,以此类推)
void getNext(string s1)
{
	next1[0] = -1;
	int t;
	int len1 = s1.size();
	for(int j = 1; j < len1; j++)
	{
		t = next1[j-1];
		while(t >= 0 && s1[j] != s1[t + 1])
		{
			t = next1[t];
		}
		if(s1[j] == s1[t + 1])
		{
			next1[j] = t + 1;
		}
		else
		{
			next1[j] = -1;
		}
	}
	
	/*
	cout<<"---"<<endl;
	for(int i = 0;i<len1;i++)
	{
		cout<<next1[i]<<endl;
	}
	cout<<"---"<<endl;
	*/
}
//s1表示模式串 s2表示原串
int kmp(string s1, string s2)
{
	int	cnt = 0;
	int i = 0, j = 0;
	int len1,len2;
	len1 = s1.size();
	len2 = s2.size();
	while(i < len2)
	{
		if(s1[j]==s2[i])
		{
			j++;i++;
			if(j == len1)
			{
				cnt++;
				j = next1[j-1] + 1;
			}
			
		}
		else
		{
			if(j == 0) 
				i++;
			else
				j = next1[j-1] + 1;
		}
	}	
	return cnt;
}
int main() {
	int T;
	cin>>T;
	string s1, s2;
	while(T--)
	{
		cin>>s1>>s2;
		getNext(s1);
		int cnt = kmp(s1,s2);
		cout<<cnt<<endl;
	}
	return 0;
}

算法练习2 P3375 【模板】KMP字符串匹配
https://www.luogu.org/problemnew/show/P3375

#include <iostream>
using namespace std;
#define MAXN 1000005
int next1[MAXN];

int main() {
	// your code goes here
	//s1表示原串 s2表示模式串
	string s1,s2;
	cin>>s1>>s2;
	int len1 = s1.size();
	int len2 = s2.size();
	int t;
	next1[0] = -1;
	for(int j = 1; j < len2; j++)
	{
		t = next1[j - 1];
		while(t >= 0 && s2[t + 1] != s2[j])
		{
			t = next1[t];
		}
		if(s2[t + 1] == s2[j])
		{
			next1[j] = t + 1;
		}
		else
		{
			next1[j] = -1;
		}
	}
	
	int i=0, j=0;
	while(i < len1)
	{
		if(s1[i] == s2[j])
		{
			i++; j++;
			if(j == len2)
			{
				cout<<i - len2 + 1<<endl;
				j = next1[j-1] + 1;
			}
		}
		else
		{
			if(j==0)
			{
				i++;
			}
			else{
				j = next1[j-1] + 1;
			}
		}
	}
	for(int j = 0; j< len2; j++)
	{
		cout<< next1[j] + 1;
		if(j == len2 - 1)
		{
			cout<<endl;
		}
		else
		{
			cout<<" ";
		}
	}
	return 0;
}

算法练习3 POJ3416 Oulipo
http://poj.org/problem?id=3461
这道题比较尴尬,用string存字符串会显示Time Limit Exceeded,索性改成char数组才过的

#include <iostream>
#include<cstring>
#include<cstdio>
#include<string>
using namespace std;
#define MAXN 100005
int next1[MAXN];
char p[MAXN],s[MAXN*10];
void getNext(string p)
{
	next1[0]= -1;
	int t;
	int len = p.size();
	for(int j = 1; j < len; j++)
	{
		t = next1[j - 1];
		while(t >= 0 && p[t + 1] != p[j])
		{
			t = next1[t];
		}
		if(p[t + 1] == p[j])
		{
			next1[j] = t + 1;
		}
		else
		{
			next1[j] = -1;
		}
	}
}
int kmp(string p, string s)
{
	int lenp = p.size();
	int lens = s.size();
	int i = 0, j = 0;
	int cnt = 0;
	while(i < lens)
	{
		if(p[j] == s[i])
		{
			i++; j++;
			if(j == lenp)
			{
				cnt++;
				j = next1[j - 1] + 1;
			}
		}
		else
		{
			if(j == 0)
			{
				i++;
			}
			else
			{
				j = next1[j - 1] + 1;
			}
		}
	}
	return cnt;
}
int main() {
	// your code goes here
	int T, cnt;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%s%s",p,s);
		getNext(p);
		cnt = kmp(p,s);
		printf("%d\n",cnt);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值