串的模式匹配:两种方法BF(Brute Force)和KMP(Knuth-Morris-Pratt)

前提:模式匹配的在干嘛?

​  答:模式匹配的目的就是找到字串在在主串中的位置,根据结束条件的不同可以区分成两种情景,第一:找到字串第一次出现的的位置,第二:字串出现的次数,这里我们只讨论第一种。

关于两个指针i和j的解释:在全文都是这个逻辑

 i 和 j 分别作为主串S 和 模式串T中当前正待比较的字符的位置。

1.BF暴力匹配

 前提:暴力匹配很好理解,里面的数学逻辑也比较简单这个我简单赘述一下。

在这里插入图片描述

这个是王道书上的代码。

 1.关于两个指针i和j的解释:

  i 和 j 分别作为主串S 和 模式串T中当前正待比较的字符的位置。

 2.关于else中 i = i - j + 2的数学模型:

在这里插入图片描述

2.KMP匹配

 前提1:为什么提出KMP算法?

​  因为BF算法太过于耗费时间,然而从BF算法的过程中我们能够提取到更快捷的方法。

注意:KMP算法是在BF算法和部分匹配值两者结合获得的灵感,看我下文解释。

 前提2: 字符串的前缀、后缀和部分匹配值三者的概念和关系。

  概念:
   字符串前缀:除最后一个字符以外,所有”头部字串“。
   字符串后缀:除第一个字符以外,所有”尾部字串“。
   部分匹配值:字符串前后缀最长相等的前后缀。

注:头部字串表示一定是从头开始必须包含头元素的不间断字串

​ 尾部字串表示一定是从结尾开始必须包含尾元素的不间断字串

  例子:” ababa “

在这里插入图片描述

对应PM表(Partical Match):
在这里插入图片描述

  重点

​    需要强调,这里的PM表是数组的形式,下标是以0开始的,从而也就引发下文对PM的第一次优化。

​    假设当我们匹配到 ab 时子串的 b字符与主串中对应位置字符匹配失败,我们发现已匹配字符串最后一个元素 a 所对应的部分匹配值是在PM表中下标是 字符a 的对应编号 - 1的位置。,所有我们对PM表进行第一次优化,进而有了next表

 注: 要理解对应匹配值讲的是一个字串前后缀的匹配关系。

  部分匹配值的使用
   结论:在KMP算法中 i 指针是不回退的(既主串始终没有回退),只有 j 指针去寻找匹配失败后的位置

​     j = 移动位数 + 1

​     移动位数 = 已匹配字符数 - 对应的部分匹配值(已匹配字符的部分匹配值)

  原理:

在这里插入图片描述

  通过上述我们发现可以不用移动 i 指针,直接移动 j 指针,就可以完成匹配,那移动的规律我们也能从上述中找到:

   语言描述:

​      既当某个字符匹配失败,我们只需要让 j 移动到已经匹配子串中对应匹配值所对应的匹配位置,既当上述图片①在最后一个c字符匹配失败后,已经匹配子串abca中前后缀相同的最长的位置既 ④的位置,此时 j的指针应该指在④的第一个字符a的后边

   数学计算:

​      上述我们分两步计算:

​       第一:子串的移动。既跳过② ③直接到④的数学公式

​       第二:指针 j 的位置。既当前要重新比较新位置是否匹配。

​       右移(移动)位数 = 已经匹配字符数 - 对应的部分匹配值

​          所以:Move = (j - 1) - PM[j-1]

解释:
  j表示当前不匹配指针的位置,所以 j-1 表示当前匹配的长度。

​  PM为什么用j-1作为下标,上文我已经在PM第一次出现的地方讲过。 我再讲一遍:PM表是数组的形式,下标是以0开始的,而j指针是从1开始的,所以已经匹配到的子串的最后一个元素对应的,所以对应的部分匹配值是在PM数组中下标是最后一个元素位置-1

那我们开始计算 j 指针:

​     j = j - Move = j - {( j -1 ) - PM[j-1] } = PM[j-1] + 1

  解释:这里为什么子串会右移?

​    这里是因为 i指针是没有回退的,当j指针指向新的位置后,就要去和i所指向的主串进行比较从而构造了一种子串移动的效果,如图:

在这里插入图片描述

  两次优化:

   第一次优化

​      是对PM[]数组进行优化:使其不用 j-1 而是直接用 j 就能找到对应部分匹配值,减少一次j-1的计算。

​     让PM的元素都往后移动一位,第一位补-1,最后一位舍去,解释如图

在这里插入图片描述

   结论:

​      优化后: j = next[j] + 1

   第二次优化:

​      让next数组中对应的元素都+1,第二次优化比较简单,目的就是在改变j指针时只需要一个next数组就好。

   结论:

​      优化后 j = next[j]

  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值