0
点赞
收藏
分享

微信扫一扫

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

以前干嘛去了 2022-04-04 阅读 76

文章目录

字符串匹配-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表示子串(模式串)长度

举报

相关推荐

0 条评论