理解KMP算法

KMP算法

有一个文本串S,和一个模式串P,现在要查找P在S中的位置

几个概念:

  1. 字符串前缀、字符串后缀、字符串前缀后缀最大公共元素长度
    在这里插入图片描述

  2. 字符串子串的最长公共元素长度
    例:ABCDABD : 2
    在这里插入图片描述

  3. Next 数组:当前字符前面字符串子串的最长公共元素长度
    在这里插入图片描述

步骤:

假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置
• 如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++,继续匹配下一个字符;
• 如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S向右移动了j - next [j] 位。(换言之,当匹配失败时,模式串向右移动的位数为:失配字符所在位置 - 失配字符对应的next 值,即移动的实际位数为:j - next[j],且此值大于等于1)。

next 数组各值的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀。例如如果next [j] = k,代表j 之前的字符串中有最大长度为k 的相同前缀后缀。

也意味着在某个字符失配时,该字符对应的next 值会告诉你下一步匹配中,模式串应该跳到哪个位置(跳到next [j] 的位置)。如果next [j] 等于0或-1,则跳到模式串的开头字符,若next [j] = k 且 k > 0,代表下次匹配跳到j 之前的某个字符,而不是跳到开头,且具体跳过了k 个字符。

代码:

  int KmpSearch(char* s, char* p)  {  
	    int i = 0;  
	    int j = 0;  
	    int sLen = strlen(s);  
	    int pLen = strlen(p);  
	    while (i < sLen && j < pLen)    {  
	        //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++      
	        if (j == -1 || s[i] == p[j])  {
	            i++;  
	            j++;  
	        }  else  {  
	    //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]      
	        //next[j]即为j所对应的next值        
	            j = next[j];  
	        }  
	    }  
	    if (j == pLen)  
	        return i - j;  
	    else  
	        return -1;  	}  

过程:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
当S[10]跟P[6]匹配失败时,KMP不是跟暴力匹配那样简单的把模式串右移一位,而是执行第②条指令:“如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]”,即j 从6变到2(我们将求得P[6],即字符D对应的next 值为2),所以相当于模式串向右移动的位数为j - next[j](j - next[j] = 6-2 = 4)。

向右移动4位后,S[10]跟P[2]继续匹配。为什么要向右移动4位呢,因为移动4位后,模式串中又有个“AB”可以继续跟S[8]S[9]对应着,从而不用让i 回溯
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

算法复杂度:

如果某个字符匹配成功,模式串首字符的位置保持不动,仅仅是i++、j++;如果匹配失配,i 不变(即 i 不回溯),模式串会跳过匹配过的next [j]个字符。整个算法最坏的情况是,当模式串首字符位于i - j的位置时才匹配成功,算法结束。
所以,如果文本串的长度为n,模式串的长度为m,那么匹配过程的时间复杂度为O(n),算上计算next的O(m)时间,KMP的整体时间复杂度为O(m + n)。

拓展:

  1. Next数组与有限状态自动机
    在这里插入图片描述
    在这里插入图片描述

  2. 算法
    BM算法从模式串的尾部开始匹配,且拥有在最坏情况下O(N)的时间复杂度。在实践中,比KMP算法的实际效能高。

  3. Sunday 算法
    比BM快。

参考:
https://blog.csdn.net/wjy0330/article/details/39589743
http://www.ituring.com.cn/article/59881

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值