【算法】KMP - 字符串匹配算法

【算法】KMP - 字符串匹配算法

[by_041]

问题模板

  • 给定两串字符串str_1str_2,判断串str_1在串str_2中出现了几次(记录每次出现的位置)

解法

对于str_1构建 nex[ ] 位移数组

  • 利用模式串内部的前缀重复性,创建一个数组nex[]

    nex[i]表示str_1[0~nex[i]]可以和str_1[(i-nex[i])~i]匹配。

  • str_1="bbbabb"为例,构造nex[]的构造如下:

    nex.clear();
    nex.resize(str_1.size());
    for(int i=0,j=nex[0]=-1;i<(int)str_1.size();nex[++i]=++j)
    {
    
    
        while(~j&&str_1[i]!=str_1[j])
            j=nex[j];
    }
下标 0 1 2 3 4 5
str_1[ ] b b b a b b
nex[ ] -1 0 1 2 0 1

利用 nex[ ] 将str_1与str_2进行模式匹配

  • 设置now_1now_2,每次操作将str_1[now_1]str_2[now_2]匹配。若成功,now变量双双加一;若失败,now_1=nex[now_1],特别的当nex[now_1]==-1时,now_2++

  • str_1="bbbabb"str_2=bbbacbbbabbbabb为例,扫描的过程如下:

下标 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
str_2[ ] b b b a c b b b a b b b a b b
第1步 【b】 b b a b b
第2步 b 【b】 b a b b
第3步 b b 【b】 a b b
第4步 b b b 【a】 b b
第5步 b b b a 【b】 b (此 nex [4] =0
第6步 【b】 b b a b b (nex [0] =-1
第7步 【b】 b b a b b
第8步 b 【b】 b a b b
第9步 b b 【b】 a b b
10 b b b 【a】 b b
11 b b b a 【b】 b
12 b b b a b 【b】 get 6
13 b 【b】 b a b b
get 10

洛谷模板题 - 模板代码

#include<bits/stdc++.h>

using namespace std;

int main()
{
    
    
	string str_1,str_2;
	cin>>str_2>>str_1;
	vector<int>nex;
	nex.resize(str_1.size()+1);
	for(int i=0,j=nex[0]=-1;i<(int)str_1.size();nex[++i]=++j)
	{
    
    
		while(~j&&str_1[i]!=str_1[j])
			j=nex[j];
	}
	vector<int>anss;
	for(int now_1=0,now_2=0;now_2<(int)str_2.size();now_2++)
	{
    
    
		while(now_1>0&&str_2[now_2]!=str_1[now_1])
			now_1=nex[now_1];
		if(str_2[now_2]==str_1[now_1])
			now_1++;
		if(now_1==(int)str_1.size())
		{
    
    
			anss.push_back(now_2-now_1+2);
			now_1=nex[now_1];
		}
	}
	for(auto i:anss)
		cout<<i<<endl;
	reverse(nex.begin(),nex.end());
	nex.pop_back();
	reverse(nex.begin(),nex.end());
	for(auto i:nex)
		cout<<i<<' ';
	cout<<endl;
	return 0;
}

代码模板

#include<iostream>
#include<cstring>
#include<string>
#include<vector>

using namespace std;

#define pattern_MAX_SIZE 1001
struct pattern	//模式串类
{
    
    
	int siz;	//模式串长度
	char str[pattern_MAX_SIZE];	//内容
	int nex[pattern_MAX_SIZE];	//nex[]功能数组
	vector<int>anss;			//存放查询结果

	void in()		//输入内容
	{
    
    
		cin>>str;
		size();
		KMP_biuld_nex();
	}
	
	void out()		//输出内容
	{
    
    
		puts(str);
	}
	
	int size()		//更新siz
	{
    
    
		return siz=strlen(str);
	}
	
	void KMP_biuld_nex()//搭建nex[]功能数组
	{
    
    
		nex[0]=-1;
		int i=1,j=0;
		while(i<siz)
		{
    
    
			while(~j&&str[j]!=str[i])
				j=nex[j];
			nex[++i]=++j;
		}
	}
	
	void KMP_match(char*astr)//模式串识别,将astr中每一次出现ptn(当前模式串)的首位置储存在成员变量anss里
	{
    
    
		anss.clear();
		for(int now_str=0,now_ptn=0,size_str=strlen(astr),size_ptn=this->siz;now_str<size_str;now_str++)
		{
    
    
			while(now_ptn>0&&astr[now_str]!=this->str[now_ptn])
				now_ptn=nex[now_ptn];
			if(this->str[now_ptn]==astr[now_str])
				now_ptn++;
			if(now_ptn==size_ptn)
			{
    
    
				anss.push_back(now_str-now_ptn+1);
				now_ptn=nex[now_ptn];
			}
		}
	}

};

int main(void)
{
    
    
	char a[1001];
	// string a;
	pattern b;
	cin>>a;
	b.in();
	
	putchar('\n');
	
	// //char a[1001];
	b.KMP_match(a);
	// // string a;
	// b.KMP_match(const_cast<char*>(a.c_str()));
	for(auto it:b.anss)
		cout<<it<<endl;

	putchar('\n');
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42710619/article/details/114769534