1.字符串匹配
问题描述,给定一个输入字符串T[1…n],需要在T[1…n]中找到所有子串P[1…m]的起始位置。
朴素解法
对字符串T做一次遍历,遍历到元素i时,进行一次判断:从i开始到i+m-1位置是否每个T中字符均和P中对应字符相等,如相等,则输出i。
评价:简单,易用。但对每个T中字符进行处理时,没能利用到之前已经遍历的字符信息,效率不高。
基于自动机的解法
对T中所有字符做一次遍历,
以T为 abababacaba,P为ababaca为例
遍历索引:1
当前字符:a
上次为止的匹配长度:0
则,a添加后,可能的最大匹配长度为1
a与P[1]比较,
a==P[1]
,则匹配长度较上次增加1,
遍历索引:2
当前字符:b
上次为止的匹配长度:1
则,b添加后,可能的最大匹配长度为2
b与P[2]比较,
b==P[2]
,则匹配长度较上次增加1
遍历索引:3
当前字符:a
上次为止的匹配长度:2
则,a添加后,可能的最大匹配长度为3
a与P[3]比较,
a==P[3]
,则匹配长度较上次增加1
遍历索引:4
当前字符:b
上次为止的匹配长度:3
则,b添加后,可能的最大匹配长度为4
b与P[4]比较,
b==P[4]
,则匹配长度较上次增加1
遍历索引:5
当前字符:a
上次为止的匹配长度:4
则,a添加后,可能的最大匹配长度为5
a与P[5]比较,
a!=P[5]
,则匹配长度不可能为5
可能的匹配长度:4,3,2,1,0
对匹配长度为4进行验证:
a != P[4]
,故匹配长度不可能为4
对匹配长度为3进行验证:
a==P[3]
,
T[4]=b == P[2]
,
T[3]=a == P[1]
,
验证通过,故处理索引5后,上次为止匹配长度调整为3
遍历索引:6
当前字符:b
上次为止的匹配长度:3
则,b添加后,可能的最大匹配长度为4
b与P[4]比较,
b==P[4]
,则匹配长度较上次加1
遍历索引:7
当前字符:a
上次为止的匹配长度4
则,a添加后,可能的最大匹配长度为5
a与P[5]比较,
a==P[5]
,则匹配长度较上次加1
遍历索引:8
当前字符:c
上次为止的匹配长度:5
则,c添加后,可能的最大匹配长度为6
c与P[6]比较,
c==P[6]
,则匹配长度较上次加1
遍历索引:9
当前字符:a
上次为止的匹配长度:6
则,a添加后,可能的最大匹配长度为7
a与P[7]比较,
a==P[7]
,则匹配长度较上次加1。匹配长度达到的7,也即达到了P的长度。故从T的索引3开始,产生一次匹配
遍历索引:10
当前字符:b
上次为止的匹配长度:7
则,b添加后,可能的最大匹配长度为7【因为匹配长度不会超过P的长度,所以不会为8】
b!=P[7],则可能的匹配长度:6,5,4,3,2,1,0
b!=P[6],则匹配长度不可能为6
b!=P[5],则匹配长度不可能为5
b==P[4]
,
b的前一字符a,a==P[3]
a的前一字符c,c!=P[2],则匹配长度不可能为4
b!=P[3],则匹配长度不可能为3
b==P[2]
,
b的前一字符a,a==P[1]
,故匹配长度为2
遍历索引:11
当前字符:a
上次为止的匹配长度:2
则,a添加后,可能的最大匹配长度为3
a==P[3]
,则匹配长度较上次加1
处理完毕,产生一次匹配,匹配位置:索引3
论证:
我们的处理是多次循环迭代的过程,
每次循环迭代开始时,我们记录了上一次迭代结束时,
上次为止的最大匹配长度:k
新输入的字符:x
则,x添加后,可能的最大匹配长度为k+1。
对此进行论证,
首先,若x==P[k+1]
,易知,此时匹配长度较上次加1,为k+1。
假设,此时的最大匹配长度len > k+1。
则,可知上次为止的最大匹配长度为len-1>k,这与我们上次为止的最大匹配长度为k相矛盾,故,假设不成立。
即,此时,最大匹配长度为k+1。
其次,若x!=P[k+1],则匹配长度不可能为k+1
可能的匹配长度:k,k-1,…,0
对此进行论证,
若匹配长度为k+1,这显示不成立
若匹配长度len>k+1,则可知上次为止的最大匹配长度为len-1>k,这与我们上次为止的最大匹配长度为k相矛盾,故,假设不成立。
故可能的最大匹配长度为:k,k-1,…,0
综合,得证。