文本串 aabaabaaf
模式串 aabaaf
问题:在文本串中aabaabaaf找到模式串aabaaf 的位置
理解暴力算法的痛点
如果使用暴力算法,模式串匹配失败时,会从头开始,文本串也会回退,效率大幅下降。
文本串 aabaabaaf
模式串 aabaaf
当b≠f的时候,匹配失败,文本串从头开始匹配,模式串也会从头开始。
KMP算法的好处:利用已匹配的信息,让模式串跳到正确位置,文本串不后退。
计算模式串的前缀表
前缀表:记录模式串中最长相同前后缀的长度,用于跳过不必要的比较。
模式串 a a b a a f 的前缀表计算:
1.前缀:指不包含最后一个字符的所有子串(如 a, aa, aab,...)
2.后缀:指不包含第一个字符的所有子串(如 f, af, aaf,...)
的比较。
3.最终部分匹配表(通常用 next 数组表示):
模式串:a a b a a f
next: [0,1,0,1,2,0]匹配过程(文本串不回头!)
初始化:文本串指针
i=0,模式串j=0逐个比较:
如果
文本[i] == 模式[j],i和j同时右移。如果不等,根据
next[j-1]的值回退j(文本串i不动!)。
具体步骤:
文本:a a b a a b a a f 模式:a a b a a f next:[0,1,0,1,2,0]
查
next[j-1] = next[4] = 2,表示已匹配部分aabaa的最长相同前后缀是aa(长度2)。所以
j回退到2(跳过前缀aa,直接从b开始比):模式回退:a a [b] a a f继续比较 文本
[i]=b和 模式[j=2]=b,匹配!继续后移:文本:a a b a a b a a f 模式: a a b a a f
最终完全匹配,返回起始位置
i - j = 3(即文本中aabaa的 第一个a的位置)。i - j = 9 - 6 = 3文本串指针
i会指向匹配结束的下一个位置(即f之后)。模式串指针
j会指向模式串的末尾(即j = len(模式串))。
为什么能跳过?
因为 next 表告诉我们:
已匹配的
aabaa中,后缀aa和前缀aa相同。所以可以直接把前缀
aa对齐到后缀aa的位置,跳过重复比较。