算法比较
对长为m的源串,长为n的子串进行匹配
算法 | 最坏时间复杂度 | 最优时间复杂度 |
---|---|---|
暴力双循环 | O(m*n) | \ |
KMP | O(m+n) | \ |
Sunday | O(m*n) | O(m/n) |
KMP算法
核心:充分利用已知的信息,通过构建部分匹配表(Partial Match Table)来控制匹配位。
可参考以下Youtube视频:
虽然懂了KMP的大概思路,但写出来的代码还是一堆bug呀,果然还是功力不够,不过还好有Sunday算法,简单易懂,速度又快!
Sunday算法
Sunday算法是对BM算法(Boyer-Moore算法)的进一步优化,是现代文字处理器中常用的字符串匹配算法。
核心:尽可能的跳过较多的字符串
参数介绍:
- 主串S
- 模式串P
- i 为主串S的的index,j为模式串P的index。
- m 指着模式串最后一位与主串对应的位置的下一位(现在不理解,可以看下面的实例)。
- slen:主串S的长度
- plen: 模式串P的长度
算法步骤
- 首先初始状况是
i=j=0
,i指着S的首位,j指着P的首位,m则指着S的第plen+1
位,及第6位 - 判断
S[i]
与P[j]
是否相等。- 若相等则
i++
,j++
,比较下一位。 - 若相等,且
j==plen-1
,也就是比较完毕了,则说明找到了目标,直接返回i-j即可。 - 若是不相等,则需要看
S[m]
字符是否在P中出现- 若没出现,则直接将j指向
S[m]
的下一位,i指向m+1的位置,j则重新置0,m则更新为 新的i+plen。 - 若出现了,还是要想办法尽可能大的将P往后滑动。首先,找到模式串P中与
S[m]
字符相等字符的位置,然后将P串中的该字符与S[m]
字符对齐。对齐时,P向右滑动了多少格,i更新的时候就加几,j则重置为0,m还是用更新后的i加plen:新i+plen。 - 更新后若出现
m>slen
的情况,说明已经比较完毕,仍没有找到目标,则return -1
。
- 若没出现,则直接将j指向
- 若相等则
实例讲解
参数
- S: string matching algorithm
- P: rithm
- slen: 25
- plen: 5
首先将i指向S首位,j指向P首位,即i=j=0
. m则指向S的第plen位,也就是第5位。
初始化 i=0, j=0, m=5, 状态如下所示
S | s | t | r | i | n | g | m | a | t | c | h | i | n | g | a | l | g | o | r | i | t | h | m | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
i | m | ||||||||||||||||||||||||
P | r | i | t | h | m | ||||||||||||||||||||
j |
比较 S[0]
与 P[0]
,发现不等,则直接看 S[5]
是否在P中出现,'rithm'
里是没有'g'
的,故直接将P
移到m
的下一位。
第一步更新后 i=6, j=0, m=11, 状态如下所示
S | s | t | r | i | n | g | m | a | t | c | h | i | n | g | a | l | g | o | r | i | t | h | m | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
i | m | ||||||||||||||||||||||||
P | r | i | t | h | m | ||||||||||||||||||||
j |
比较S[6]
与P[0]
,发现' '
不等于'r'
,且S[11]
在'rithm'
的第3位出现。则需要将P
中的'h'
与S
中的'h'
对齐,只需要将P
串向右移动两格(对应于i=m-3=8
)
第二步更新后 i=8, j=0, m=13, 状态如下所示
S | s | t | r | i | n | g | m | a | t | c | h | i | n | g | a | l | g | o | r | i | t | h | m | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
i | m | ||||||||||||||||||||||||
P | r | i | t | h | m | ||||||||||||||||||||
j |
同样S[8]!=P[0]
,且S[13]
为'n'
不存在于'rithm'
,因此直接将P滑到m的下一位
第三步更新后 i=14, j=0, m=19
S | s | t | r | i | n | g | m | a | t | c | h | i | n | g | a | l | g | o | r | i | t | h | m | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
i | m | ||||||||||||||||||||||||
P | r | i | t | h | m | ||||||||||||||||||||
j |
再次比较, S[14]!=P[0]
, 且S[19]
不在P中,再次将P滑到m的下一位。
第四步更新后 i=20, j=0, m=25
S | s | t | r | i | n | g | m | a | t | c | h | i | n | g | a | l | g | o | r | i | t | h | m | |||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
i | m | |||||||||||||||||||||||||
P | r | i | t | h | m | |||||||||||||||||||||
j |
这时候可以看到,'rithm'
是匹配上了,一步一步比较,i与j逐步加1,直至j=4
时,比较完毕,得到结果i-j=24-4=20
。
LeetCode 题源
LeetCode 28. Implement strStr()
AC 代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32class Solution {
public:
int strStr(string haystack, string needle) {
if(needle.empty()){
return 0;
}
int slen=haystack.length();
int plen=needle.length();
int i=0,j=0,k,m=plen; // i 指 haystack,j 指 needle,
while(i<slen){
if(haystack[i]!=needle[j]){
for(k=plen-1;k>=0;k--){
if(needle[k]==haystack[m])
break;
}
i=m-k;
j=0;
m=i+plen;
if(m>slen){
return -1;
}
}else{
if(j==plen-1){
return i-j;
}
i++,j++;
}
}
return -1;
}
};