1. 题目
有一个主串S={a,b,c,a,c,a,b,d,c},模式串T={a,b,d},请找出模式串在主串中第一次出现的位置
提示:不需要考虑字符串大小写问题,字符均为小写字母
2. BF算法
BF算法,又称爆发匹配算法,简单来说,就是将模式串一个一个字符与主串进行对比,直到模式串中所有的字符匹配成功。
解法思路:
1、 分别利用计数指针i和j,指示主串S和模式T中当前正待比较的字符位置,i初值为pos,j的初值为1;
2、 如果2个串均为比较到串尾,即i和j均小于等于S和T的长度时, 则循环执行以下的操作:
S[i]和T[j]比较,若相等,则i 和 j分别指示串中下一个位置,继续比较后续的字符;
若不相等,指针后退重新开始匹配. 从主串的下一个字符串(i = i – j + 2)起再重新和模式第一个字符(j = 1)比较;
3、 如果j > T.length, 说明模式T中的每个字符串依次和主串S找中的一个连续字符序列相等,则匹配成功,返回和模式T中第一个字符的字符在主串S中的序号(i-T.length);否则匹配失败,返回0;
辅助部分
核心部分
3. RK算法
相对来说,比较字母总是不如比较数字大小来的简单,那么我们是否可以将字符通过什么方式来计算出对应的数字结果呢?
我们的前辈,Rabin和Karp就很有想法的,通过设计一个哈希公式,利用字符串对应的哈希值来进行比较。即我们已知的模式串可以计算出它的哈希值,同时将主串拆分出与模式串相同长度的子串来计算哈希值,比较两个哈希值是否相等。
那么问题来了:如何将一个‘bcd’换算成一个哈希值?
通过ASCII表可以直到字母对应的ASCII值,‘a’ = 97。
字母一共有26位,我们可以设计一个26进制
bcb = ('b'-'a')*26^2 + ('c'-'a')*26^1 + ('b'-'a')*26^0;
其中的2次方,也可以认为是模式串长度m减1得来的。
上边计算字符串的哈希值的逻辑假如理解的话,那我们可以再来想一个问题:主串拆分出来的,相邻两个子串,对应的哈希值计算公式是否有交集?是否可以通过前一个子串的哈希值,来求得下一个子串呢?
我们再来看看:
假如相邻的两个字符为’bcb’和’cba’,他们的哈希计算分别为
bcb = (‘b’-‘a’)*26^2 + ('c'-'a')*26^1 + ('b'-'a')*26^0;
cba = ('c'-'a')*26^2 + ('b'-'a')*26^1 + (‘a’-‘a’)*26^0;
可以看到,‘bcb‘减去了最高位的‘b’,同时后两位的多乘了一次26,然后再加上下一个字符串的最低位’a’,得到的结果就是‘cba’的哈希值。
最终的公式
St[i] = (St[i-1] - 26^(m-1)*(S[i]-'a')) * 26 + (S[i+m]-'a')
ps:St[i]为主串中当前子串的哈希值,St[i-1]为前一个子串的哈希值,m为模式串的长度
那么,两个字符串的哈希值相等,就表示两个字符串就一定相同吗?
答案是不一定的,所以我们还需要进一步进行验证,哈希值相等时,两个字符串是否真的匹配?
辅助部分
核心部分