KMP字符串匹配算法解析

最近玩了一点服务器的东东,感觉好有趣~很简单还让人很有成就感,wow 有时间总结一下,谢谢陶龙学长的帮助。

要继续写博客啦,学习任务不能落下!!

上午看了KMP算法,有些头大,书上写的非常不清晰,一堆数学语言。之后在网上查了一下,豁然开朗,发现这是个非常有趣的一个算法~

对于字符串搜索,大家都知道最简单的暴力算法啦

暴力搜索时,每次匹配失败,在关键词字符串的游走指针都要回归到首位,不论之前指针走了多远。而指针走的越远,就代表搜索的次数越多,浪费就更大。例如对于“abcabc”和“abd”这两个字符串,第一次遍历后

a b c a b c
| | x
a b d 
此时在被搜索字符串的指针其实可以往后移动两位,直接比较
a b c a b c
  
    a b d 
为什么是两位呢?因为abd三个字母各不相同,而我们已经匹配成功了两个字母,
意味着匹配成功的这两个字母都可以越过啦!都和a不匹配。

现在的问题就是要找到向右最多可以移动的位数和这个关键字符串的关系!!
如果关键字符串是各不相同的字符,那么每次可以移动“已经匹配成功的字符数量”,也就是正在匹配的字符的序号-1。
而关键字符串中若有重复的子串,就不一样啦,这个时候就要做出调整
a b a c a b a b c
| | | x
a b a b (这个时候子串就不能向右移动三位了,因为第三个a是和第一个a匹配的,不能越过)
下一次要这样检查
a b a c a b a b c
    | 
    a b a b
这个时候,减少向右移动位数的原因就是,已检查的串(aba)的前缀串与后缀串最多已经有1个是相等的啦,所以要把1减掉;
对于一个所有字母都不一样的字符串,每一个子串(其实只需讨论前缀串),的前缀串与后缀串都永远为0,所以不用减去东西。

看到这里可能大家大概明白了“前缀”,“后缀”的含义,但还不是很清晰~

给出一个明确的定义~
前缀是指一个字符串,出去尾字符之后,全部的头部组合
    对于“abc”其前缀为[“a”,”ab”]
后缀正好相反。
下面就要处理任意字符串的问题啦!
    首先对于作为关键词的字符串要进行预处理,获取在任一位(假设第n位)匹配失败时,在被搜索字符串上,向右移动的次数。

    这个位置最多可以向右移动n-1位(如果前n-1位没有匹配的前后缀的话),当前n-1位有匹配的前后缀时,要再减去最长的匹配的前后缀字符串的长度(设为x),即在该位置匹配失败时,向右移动n-1-x;x最大为n-2;

x又要怎么求出来呢?对于n-1长的前缀串,第一位与尾部比较,++,–…x从0开始++,所得的x赋值给第n的位置;对于每一位都这么做就好了,第一位赋值为0。再用序号-1再减去对应的x就得到了在第n位匹配失败时,关键字符串向右移动位数的数组!

就差一步啦,在我们的关键词字符串上的指针,要指到哪里去呢?回溯的话咱们又白费一番功夫啦!这个指针,就是要指向第x位去!这样看来,前缀和后缀共同长度更多的话,也不是个坏事哦!

所以,我们应该储存的数组是每一位的“x”,在关键词字符串第n位匹配失败时,关键词字符串首位向右移动n-1-x位,在下一位比较关键词字符串的第x位!

复杂度为O(m+n)~

可能还不是很清晰,还望指教~

点赞