kmp专题

kmp即字符串匹配,时间复杂度O(M+N)。

核心为求匹配的字符串的next[]数组(以当前位置结束的最长前缀的位置),代码如下:

void getnext()
{
	int i=0,j=-1,len=strlen(str2);
		a[0]=-1;
		while(i<len)
		{
			if(j==-1||str2[i]==str2[j])
				a[++i]=++j;
			else
				j=a[j];
		}
}

裸题:hdu1686

查一串字符串中某个单词的出现次数。 

输入

第一行输入一个 T ,代表数据数目。

每组数据第一行输入需要查找的单词。

第二行输入这个较长的字符串(长度小于1000010)。

输出

每组数据输出一个 n ,代表要这个单词出现的次数。

样例输入

3
ABCD
ABCD
AZA
AZAZAZA
HIDSJ
FJOSJWHABNMDS

样例输出

1
3
0

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
char str1[maxn],str2[maxn];
int a[maxn];

void getnext()
{
	int i=0,j=-1,len=strlen(str2);
		a[0]=-1;
		while(i<len)
		{
			if(j==-1||str2[i]==str2[j])
				a[++i]=++j;
			else
				j=a[j];
		}
}

int kmp()
{
	int ans=0,i=0,j=0,l1=strlen(str1),l2=strlen(str2);
	while(i<l1)
	{
		if(j==-1||str1[i]==str2[j])
			i++,j++;
		else
			j=a[j];
		if(j==l2)ans++;
	}
	return ans;
}

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		cin>>str2>>str1;
		getnext();
		cout<<kmp()<<endl;
	}
}

hdu2594 

题意:
给两个字符串s1,s2,求最长的s1前缀匹配s2后缀的字符串,以及长度

输入

输入有多组数据。

每组数据有两行,分别为两个人的名字(名字全由英文组成,名字长度不超过50000)。

输出

求出前一个人的名字的前缀,与后一个人的名字的前缀,最大的相同数目。

若不为0,还需输出其相同的几位字母,并且字母在数字前面,中间由空格隔开。

样例输入

mike
aniom
kiava
dvakia
dasds
fdsgh

样例输出

m 1
kia 3
0

思路:先把两串合并在一起,然后求next[]数组,然后判断next[]最后一位,如果长度>最短串的长度,就缩进到前面(即切断过长的部分)

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=200010;
string str1,str2,str3;
int a[maxn];

void getnext()
{
	int i=0,j=-1,len=str3.size();
		a[0]=-1;
		while(i<len)
		{
			if(j==-1||str3[i]==str3[j])
				a[++i]=++j;
			else
				j=a[j];
		}
}
int main()
{
	while(cin>>str1>>str2)
	{

		str3=str1+str2;
		int lena=str1.size();
		int lenb=str2.size();
		int lenc=str3.size();
		int ab=min(lena,lenb);
		getnext();
		while(a[lenc]>ab)
			lenc=a[lenc];
		if(a[lenc])
			{
				for(int i=0;i<a[lenc];i++)
							cout<<str1[i];
					cout<<" "<<a[lenc]<<endl;
			}
		else
		{
			cout<<a[lenc]<<endl;
		}
		str1.clear();
		str2.clear();
		str3.clear();
	}
}

 hdu4763

题意描述:给定一个字符串,找出长度最大的子串,使开始、中间、结尾至少都包含它?

思路:

从大到小枚举子串长度,先判断结尾和开始是否一样,如果一样,则使用kmp判断中间是否含有子串,如果有就是答案

代码:

#include<bits/stdc++.h>
using namespace std;
char s[1000005];
int nxt[1000005];
int len;
set<int> st;
void getnxt()
{
    memset(nxt,-1,sizeof(nxt));
    nxt[0] = -1; int j = -1;
    for(int i = 0; i < len;){
        if(j == -1||s[i] == s[j])nxt[++i] = ++j;
        else j = nxt[j];
    }
}

void getback()
{
    int p = nxt[len-1];
    while(p>=0){
        if(s[len-1] == s[p]){
            st.insert(p+1);
        }
        p = nxt[p];
    }
}

void solve()
{
    int ans = 0;
    for(int i = len-2;i>=0;--i){
        int p = nxt[i];
        while(p>=0){
            if(s[i] == s[p] && st.find(p+1)!=st.end()){
                if(len - 1 -p > i && p < i-p){
                    ans = max(ans,p+1);
                }
            }
            p = nxt[p];
        }
    }
    printf("%d\n",ans);
}

int main()
{
    int T;
    cin>>T;
    while(T--){
        cin>>s;
        st.clear();
        len = strlen(s);
        getnxt();
        getback();
        solve();
    }
    return 0;
}

以上为kmp总结例题。 

猜你喜欢

转载自blog.csdn.net/sjs_caomei/article/details/81811180
kmp
今日推荐