其中,Target为主串,Pattern为子串(模式串),如果在主串Target的第pos个位置后存在与子串Pattern相同的子串,返回它在主串Target中第pos个字符后第一次出现的位置,否则返回-1
1、 BF算法(Brute-Force,最基本的字符串匹配算法)
int BF(const string &Target,const string &Pattern,int pos)
{
int i = pos; //主串当前正待比较的位置,初始为pos
int j = 0; //子串当前正待比较的位置,初始为0
int Tlen = Target.size(); //主串长度
int Plen = Pattern.size(); //子串长度
while(i < Tlen && j < Plen)
{
if(Target[i] == Pattern[j]) //如果当前字符相同,则继续向下比较
{
i++;
j++;
}
else //如果当前字符不同,则i和j回退,重新进行匹配
{
i = i-j+1; //Target退回下一轮开始比较的位置
j = 0; //Pattern退回到子串开始处
}
}
if(j >= Plen)
return i - Plen; //返回匹配第一个位置
else
return -1;
}
2、KMP
上述算法的时间复杂度之所以大,是由于索引指针的回溯引起的,针对以上不足,便有了KMP算法。KMP算法可以在O(Plen+Tlen)的时间数量级上完成串的模式匹配操作。其改进之处在于:每一趟比较重出现字符不等时,不需要回溯索引指针i,而是利用已经得到的部分匹配的结果将子串向右滑动尽可能远的距离,继续进行比较。它的时间复杂度为O(Plen+Tlen),空间复杂度为O(Plen)
KMP算法的关键是利用匹配失败后的信息(已经匹配的部分中的对称信息),尽量减少模式串(待搜索词)与文本串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,该函数本身包含了模式串的局部匹配信息。
void GetNext(const string &Pattern,int next[],int len)
{
int j = 0;
int k = -1;
next[0] = -1;
while(j < len-1)
{ //p[k]表示前缀,p[j]表示后缀
if(k == -1 || Pattern[j] == Pattern[k])
{ //如果满足上面分析的Pk = Pj的情况,则继续比较下一个字符,
//并得next[j+1]=next[j]+1
j++;
k++;
next[j] = k;
}
else
{ //如果符合上面分析的第2种情况,则依据next[k]继续寻找下一个比较的位置
k = next[k];
}
}
}
int KMP(const string &Target,const string &Pattern,int pos,int next[])
{
int i = pos; //主串当前正待比较的位置,初始为pos
int j = 0; //子串当前正待比较的位置,初始为0
int Tlen = Target.size(); //主串长度
int Plen = Pattern.size(); //子串长度
while(i < Tlen && j < Plen)
{
if(j==-1 || Target[i] == Pattern[j])
{ //如果当前字符相同,或者在子串的第一个字符处失配,则继续向下比较
i++;
j++;
}
else //如果当前字符不同,则i保持不变,j变为下一个开始比较的位置
{
//next数组是KMP算法的关键,i不回退,
//而是继续与子串中的nex[j]位置的字符进行比较
j = next[j];
}
}
if(j >= Plen)
return i - Plen;
else
return -1;
}