字符串匹配
来源:互联网 发布:php免费源码下载 编辑:程序博客网 时间:2024/06/01 07:14
一、问题定义
已知一个源字符串T,和一个目标字符串P,其中T的长度大于等于P的长度,求T中与P完全相同的子串的位置。
例:已知T=” abbabcabbababca” ,P=”abca”则结果为3和12
二、问题求解
下面介绍了解决该问题的四种方法,即朴素算法、Rabin_Karp算法、有限自动机算法、KMP算法。一下算法中T的长度为n,P的长度为m。
1. 朴素算法
(1) 基本思想
(a) 将T分解成n-m+1个字符串;
(b) 分别与P中的字符逐一的比较,记录完全相等的字符串;
(c) 返回所有完全相等的字符串的起始位置。
(2) 主代码
int pos = 0;
for (i=0; i<n-m+1; ++i)
{
for (j=0; j<m; ++j)
{
if (P[j] !=T[i+j])
break;
}
if (j == m)
{
s[pos++] = i;
}
}
s集合中所有的数据即为所求结果。
(3) 时间复杂度
每一个字符串的匹配最长时间为m,因此最坏时间复杂度O((n-m+1)m)
2. Rabin_Karp算法
(1) 基本思想
i. 将目标字符串P映射成一个数值p;
ii. 将源字符串T映射成n-m+1个数值t1, t2, ……,tn-m+1;
iii. 若p=tq,则tq所在的第一个位置为正确结果。
(2) 转换方法
i. 扫描源字符串找出字符串中包含的不同字符串的个数d;
ii. p=dm-1P[1]+dm-2P[2]+…+dP[m-1]+P[m]
iii. t0=dm-1T[1]+dm-2T[2]+...+dT[m-1]+T[m]
(3) 主代码
int str_switch_to_int(CStringstr, int n,int m)
{
int temp = 0;
for (int i=n; i<m+n; ++i)
{
temp = temp*10 + str[i];
}
return temp;
}
void match()
{
p = str_switch_to_int(P,0,m);
int pos = 0;
for (int i=0; i<n-m+1; ++i)
{
t[i] =str_switch_to_int(T,i,m);
}
for (int i=0; i<n-m+1; ++i)
{
if (p == t[i])
{
s[pos++] = i;
}
}
}
s集合中所有的数据即为所求结果。
(4) 时间复杂度
从match函数易得时间复杂度为O(n-m+1)。
3. 有限自动机算法
(1) 基本思想
i. 对目标字符串构造出一个字符串匹配的有限自动机;
ii. 对源字符串进行扫描;
iii. 当自动机的状态变为A中的一个元素时产生一个结果。
(2) 有限自动机
i. 定义:M=(Q,q0,A,∑,δ)其中,Q表示状态的有限集合,q0表示出初始状态,A输出状态集合,∑目标字符串的字符集,δ表示状态转移函数。
ii. 例:∑=abcd;
则有四种状态,分别为q0=∅,q1={a},q2={ab},q3={abc}, q4={abcd};
初始状态q0=∅;
状态的集合Q={q0,q1,q2,q3,q4};
输出的状态集A={q4}
状态转移函数δ(q0,a) = q1, δ(q1,b) = q2, δ(q2,c)= q3, δ(q3,d) = q4
(3) 构造自动机方法
构造自动机最困难的就是确定状态转移函数,即求解δ(qp,x) = ?,其中x为字符集∑中的任意一个字符,qp为状态集中的任意一种状态,下面举例描述自动机状态转移函数的求解方法。
i. ∑=abc,q0=∅,q1={a},q2={ab},q3={abc}
ii. δ(q0,a)= q1,δ(q0,b) = q0,δ(q0,c) = q0
iii. δ(q1,a)= q1,δ(q1,b) = q2,δ(q1,c) = q0
iv. δ(q2,a)= q0,δ(q2,b) = q0,δ(q2,c) = q3
v. δ(q3,a)= q1,δ(q3,b) = q0,δ(q3,c) = q0
则得到表
输入
状态
a
b
c
0
1
0
0
1
0
2
2
0
0
3
3
1
0
0
自动机的求解过程称为预处理,易得预处理时间复杂度为O(m3|∑|)。
(4) 时间复杂度
匹配只需从前到后扫描一遍源字符串T即可,因此时间复杂度O(n),而预处理时间复杂度是O(m3|∑|)。
(5) 优缺点
优点:源字符串不回溯,匹配时间短
缺点:构造自动机代价大
4. KMP算法
(1) KMP是三位设计人员Knuth、Morris、Pratt的首字母的组合。
(2) 主代码
i. void KMP_getNext()
{
int i,q = 0;
next[1] = 0;
for (i=2; i<=plenth;++i)
{
while ((q>0)&&(p[q+1]!=p[i]))
q = next[q];
if (p[q+1]==p[i]) q++;
next[i] = q;
}
}
voidKMP_match()
{
int i,q=0;
int pos=0;
for (i=1; i<=tlength; ++i)
{
while((q>0)&&(p[q+1]!=t[i]))
q=next[q];
if (p[q+1]==p[i]) q++;
if (q == plength)
{
q=next[q];
s[pos++] = i-plength;
}
}
}
(3) 时间复杂度
预处理时间O(m),匹配时间O(n)
三、小结
各算法时间复杂度比较
预处理时间
匹配时间
朴素算法
O((n-m+1)m)
Rabin_Karp算法
O(m)
O(n+m)
有限自动机算法
O(m3|∑|)
O(n)
KMP算法
O(m)
O(n)
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配...
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配
- 字符串匹配
- JS时间
- 设计模式之7 command模式和state模式,调停者模式,门面模式
- 散记-extern
- Oracle DataPump”EXCLUDE“参数和限制为4000字节
- SQL Server数据库中批量替换数据的方法
- 字符串匹配
- ARM汇编之寄存器
- ios 内存点滴
- C#中的方括号的语法及作用
- Oracle开发专题之:%TYPE 和 %ROWTYPE
- error LNK2005: _DllMain@12 已经在 XXXX.obj 中定义
- Emmet 学习之路 - 1 工具安装
- WPF与输入法冲突研究之三:韩文输入法在不同平台,WinForm/WPF下的区别
- 颜色 16进制对照表