面试算法 字符串匹配 算法:暴力算法,哈希算法 , KMP 算法

1.题目:字符串匹配 



2.算法:
1.暴力算法
2.哈希算法匹配
3.KMP 算法


3.算法思想:(看代码!! )

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)

简介

KMP算法是三位学者在 Brute-Force算法的基础上同时提出的模式匹配的改进算法。Brute- Force算法在模式串中有多个字符和主串中的若干个连续字符比较都相等,但最后一个字符比较不相等时,主串的比较位置需要回退。KMP算法在上述情况下,主串位置不需要回退,从而可以大大提高效率 [2]  。

字符串的模式匹配

字符串的模式匹配是一种常用的运算。所谓模式匹配,可以简单地理解为在目标(字符串)中寻找一个给定的模式(也是字符串),返回目标和模式匹配的第一个子串的首字符位置。通常目标串比较大,而模式串则比较短小 [3]  

模式匹配的类型

(1)精确匹配

如果在目标T中至少一处存在模式P,则称匹配成功,否则即使目标与模式只有一个字符不同也不能称为匹配成功,即匹配失败。给定一个字符或符号组成的字符串目标对象T和一个字符串模式P,模式匹配的目的是在目标T中搜索与模式P完全相同的子串,返回T和P匹配的第一个字符串的首字母位置 [3]  。

(2)近似匹配

如果模式P与目标T(或其子串)存在某种程度的相似,则认为匹配成功。常用的衡量字符串相似度的方法是根据一个串转换成另一个串所需的基本操作数目来确定。基本操作由字符串的插入、删除和替换来组成 [3]  。

KMP模式匹配算法

KMP算法是一种改进的字符串匹配算法,其关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的明 [4]  。

求得模式的特征向量之后,基于特征分析的快速模式匹配算法(KMP模式匹配算法)与朴素匹配算法类似,只是在每次匹配过程中发生某次失配时,不再单纯地把模式后移一位,而是根据当前字符的特征数来决定模式右移的位数 [3]  


代码:

/*************************************************
作者:She001
时间:2022/9/5
题目:字符串匹配 
算法:
1.暴力算法
2.哈希算法匹配
3.KMP 算法
 

***************************************************/

#include<bits/stdc++.h>
using namespace std;
//
//算法:暴力算法
//每个子字符串 一个一个的字符 匹配 
//从第一个字符开始 


//匹配函数 
bool pipei(char nn[],char mm[],int a)//nn  是主的字符串  ,  mm 是需要匹配的字符串   a 开始匹配的地方 
{
	int  b=strlen(mm);
	int j=0;
	for(int i=a;i<a+b;i++)
	{
		if(nn[i]!=mm[j])
		{
			return false;
		}
		j++;
	}
	return true;
	
}   

int fangfa_1(char nn[],char mm[])//nn  是主的字符串  ,  mm 是需要匹配的字符串 
{
	int a=strlen(nn);
	int b=strlen(mm);
	for(int i=0;i<a;i++)
	{
		if(pipei(nn,mm,i)==true)
		{
			return i+1;	
		}	
	} 
	return -1;//没有对应的字串	
} 



//哈希算法的字符串匹配
//首先算出每个对应匹配字串长度的  主串空间的每个字串 (小心哈希冲突)
int fangfa_2(char nn[],char mm[],const int n)//nn  主串,   mm  子串,   n  哈希值的数量  也是 nn 数组的长度 
{
	int b=strlen(mm);//求出  mm 字串的长度 
	int num[n];//建立一个数组存放哈希表
	int sum=0;//用于计算  nn 数组的哈希表 
	for(int i=0;i<b;i++)//确定第一个sum   等下好算一些 
	{
		sum+=(int)nn[i];//加一个强转,好一些 
	}
	int pp=0;//计算字串的哈希数字
	for(int i=0;i<b;i++)//字串的哈希数值计算 
	{
		pp+=(int)mm[i];	
	}

	
	
	//计算主串里面每个 值的哈希数值 
	for(int i=1;i<n-b;i++)//i=0  的哈希数  就是 sum  ,所以我们只要从 i == 1 开始计算 
	{
		sum=sum-nn[i-1]+nn[i+b-1];
		num[i]=sum;//记录 哈希值 
	}
	
	for(int i=0;i<n;i++)
	{
		if(num[i]==pp)
		{
			if(pipei(nn,mm,i)==true)
			{
				return i+1;	
			} 
		}
	} 
	
	return -1;
}

/kmp 算法,首先我的算法速度

//建立  next 数组
void fangfa_3_1(int *next,char mm[])//next  开辟空间的整型数组,   mm  字串
{
	int i=0;
	int j=-1;
	next[0]=-1;//初始化数据
	int a=strlen(mm);
	while(i<a-1)
	{
		if(j==-1  || mm[i]== mm[j])//这里保证可以连加, 与字符串的前进, 我们一直相对比的是 前面的字符串 
		{
			j++;
			i++;
			next[i]=j;//赋值,  当这个值是 0  的时候没有可能是跳板  跳到 next[0]  j==-1  到这里来	
		}
		else
		{
			j=next[j];	
		}	
	}	
}

int fangfa_3(char nn[],char mm[],int *next)
{
	int i=0;
	int j=0;
	int a=strlen(nn);//长度计算 
	int b=strlen(mm);
	while(i<a && j<b)//停止寻找的条件 
	{
		if(j==-1 || nn[i]==mm[j])//往前寻找的条件,,数值相等  或者 j==-1 从字串的 0的位置  开始匹配u 
		{
			i++;
			j++;
		}
		else
		{
			j=next[j];//移动字串  到对应的地方 
		}
	}
	if(j==b)
	{
		return i-j+1;	//返回开始的地址 
	}
	else
	{
		return -1;	//没有对应字串   返回  -1 
	}	
	
 } 

 
 
 


int main()
{
	char nn[]="aabnkiopfspfafafdshdasdsh";
	char mm[]="nkiop";//能匹配到的字符串 
	char mm1[]="pppppppppp";//匹配不到的字串
	int n=strlen(nn);
	int a=fangfa_1(nn,mm);
	int a1=fangfa_1(nn,mm1);
	cout<<"a = "<<a<<endl;
	cout<<"a1 = "<<a1<<endl; 
	
	int b=fangfa_2(nn,mm,n);
	int b1=fangfa_2(nn,mm1,n);
	cout<<"b = "<<b<<endl;
	cout<<"b1 = "<<b1<<endl; 
	
	int * next=new int[sizeof(mm)];//开辟空间 
	int * next1=new int[sizeof(mm1)];//开辟空间 
	
	fangfa_3_1(next,mm);//得到next 的数组 
	fangfa_3_1(next1,mm1);//得到next 的数组 
	
	int c=fangfa_3(nn,mm,next);
	int c1=fangfa_3(nn,mm1,next1);
	cout<<"c = "<<c<<endl;
	cout<<"c1 = "<<c1<<endl;  
	 
	
	return 	0;
} 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值