字符串匹配与KMP算法

LeetCode之字符串匹配与KMP算法


参考: J.Boxer’s Blog: The Knuth-Morris-Pratt Algorithm in my own words.

算法背景

在计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串 S 内查找一个词 W 的出现位置。 此算法通过运用对这个词在不匹配时本身就包含足够的信息来确定下一个匹配将在哪里开始的发现,从而避免重新检查先前匹配的字符。
——from 维基百科

部分匹配表

下面,给出一个模式“abababca”的部分匹配表:

char:  | a | b | a | b | a | b | c | a |
index: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 
value: | 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 |

如果我有八个字符的模式(在此示例中,假设为“ abababca”),则我的部分匹配表将包含八个单元格。 如果我查看表格中的第8个单元,则对整个模式(“ abababca”)感兴趣。 如果我查看表格中的第七个单元格,则只对模式中的前七个字符感兴趣(“ abababc”); 第八个(“ a”)无关紧要,不管它来自哪里。 对于第六个,也同样如此。。。

下面介绍==“部分匹配表”==是如何产生的。

首先,要了解两个概念:“前缀"和"后缀”。

前缀”——指除了最后一个字符以外,一个字符串的全部头部组合;
后缀”——指除了第一个字符以外,一个字符串的全部尾部组合。

"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以abababca为例,

  • [a] 的前缀和后缀都是空集,共有最长的元素长度为0;
  • [ab] 的前缀为[a],后缀为[b],共有最长的元素长度为0;
  • [aba] 的前缀为[a, ab],后缀为[ba, a],共有最长的元素长度为0;
  • [abab] 的前缀为[a, ab, aba],后缀为[bab, ab, b],共有最长的元素长度为2;
  • [ababa]的前缀为[a, ab, aba, abab],后缀为[baba, aba, ba, a,共有最长的元素长度为3;
  • [ababab]的前缀为[a, ab, aba, abab, ababa],后缀为[babab, abab, bab, ab, b],共有最长的元素长度为4;
  • [abababc]:由于其每个后缀都会包含’c’,而每个前缀都不会包含’c’,所以肯定无共有元素,其长度为0;
  • [abababca]的前缀为[a, ab, aba, abab, ababa, ababab, abababc],后缀为[bababca, ababca, babca, abca, bca, ca, a],共有最长的元素长度为1。

如何使用“部分匹配表”

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

char:  | a | b | a | b | a | b | c | a |
index: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 
value: | 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 |

假设搜索的文本如下:

bacbababaabcbab
    |||||
    abababca

此时已匹配的[ababa] 长度为5,下一个模式为b,其对应的value==2,所以接下来移动的距离为 5 − 2 = 3 5-2=3 52=3. 如下所示:

// x denotes a skip
bacbababaabcbab
    xx|||
      abababca
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值