字符串匹配(2)----KMP算法

本文深入探讨了KMP算法,一种用于在一个文本串中查找模式串出现位置的高效算法。核心思想是避免不必要的主串回溯,利用模式串的已匹配信息确定下一步匹配位置。代码实现展示了如何获取模式串的next数组并进行匹配。测试与复杂度分析表明,KMP算法的时间复杂度为O(n+m),空间复杂度为O(m)。
摘要由CSDN通过智能技术生成

字符串匹配-KMP算法

我们将介绍KMP算法进行字符串匹配,Knuth-Morris-Oratt字符串查找算法,主要用于在一个文本串(主串)查找一个模式串(子串)的出现位置。
KMP算法的核心主要在于

  • 主串的 i 绝不后退
  • 模式匹配串只和子串有关
    在这里插入图片描述
算法流程
  1. 假设现在有一文本串S匹配到 i 位置,模式串p匹配到 j 位置:
  • 如果当前字符匹配成功,则令i++,j++,然后继续匹配下一个字符;

  • 如果匹配失败,通过观察失配之前匹配成功的那些字符,可以分为两种情况:

    • 1.互不相等的情况,i就可以不用回退
      在这里插入图片描述
      在这种情况下,i即使回退了,也是一定会发生匹配失败的情况,无意义。

    • 2.如果在失配时,失配前的字符串互有相等情况,i可能需要向前回退,之不过,我们只要证明左绿那条线和上橙那条线相等,那么i也就可以不用回退,而是让j不在回退到0,而是回退到一个合适的位置,去代替掉
      在这里插入图片描述

    代码实现
//KMP算法
//模式匹配串next
int* Get_Next(const char* sub)
{
	assert(sub != NULL);
	int len = strlen(sub);
	int* next = (int*)malloc(sizeof(int)*len);
	assert(next != NULL);
	next[0] = -1;
	next[1] = 0;
	int k = next[1];
	int j = 1;//通过已知推位置  j代表已知位置  j+1代表要推的未知位置
	while ( j + 1 < len)
	{
		if (k == -1 || sub[j] == sub[k])
		{
			k++;
			j++;
			next[j] = k;
		}
		else
		{
			k = next[k];
		}
	}
	return next;
}
//KMP算法的主串,由于i打死不回退,只会遍历一遍 整体时间复杂度O(n+m)
int KMP_search(const char* str,const char* sub,int pos)
{
	assert(str != NULL && sub != NULL && pos >= 0 && pos < strlen(str));
	int i = pos;
	int j = 0;
	int len_str = strlen(str);  //保存主串有效长度
	int len_sub = strlen(sub);  //保存子串有效长度
	int* next = Get_Next(sub);
	while (i < len_str && j < len_sub)
	{
		if (j == -1 || str[i] == sub[j])
		{
			i++;
			j++;

		}
		else
		{
			j = next[j];
		}
	}
	//此时数据已经遍历完,要么找到,要么没有找到
	if (j < len_sub)
	{
		return -1;
	}
	else
	{
		return i - j;
	}
}
测试

我们输入一串字符串主串以及要匹配的子串,若匹配成功,将返回匹配成功的主串的下标位置。
在这里插入图片描述

算法复杂度分析

时间复杂度: O ( n + m ) O(n+m) O(n+m) n表示主串长度,m表示子串长度
空间复杂度: O ( m ) O(m) O(m) m表示子串(模式串)长度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值