在单字符串匹配算法的领域中,有两种为人熟知的算法:KMP(看毛片)和BM算法,这两种算法虽然经典,不过难码。实际上许多简单的算法速度也是飞快。于是就让我们来认识一下BM的简化版——Horspool,效率比KMP、BM都快,还好理解。
原理
先来定义一些东西(S,原串;P,匹配串;‘|’匹配成功;‘#’匹配失败
)
Horspool看是否匹配时是从后往前扫描的,若全部匹配,则找到一个可匹配的方案free话,若有一个不匹配,则当前方案不存在free话真多。这时就要分情况讨论了。
情况一:
在下例情况中,称S中的‘d’为关键字符,就是P最后一个字符在S中的匹配字符。若P中除尾字符外没有与关键字符相同的字符,显然应该将P向后推len(P)个位置。
S - *****bcd*******
#||
P - 2333acd
--> 2333acd
情况二:
若P中除尾字符外有与关键字符相同的字符,显然应该将P向后推到P中最靠右的关键字符与S中的关键字符对齐。
S - *****bcd*******
#||
P - 233dacd
--> 233dacd
自我感觉比BM好多了,简洁高效。
代码
//实现查找S中有多少个与P完全相同的子串
#include<cstdio>
#include<cstring>
using namespace std;
char S[1000],P[1000];
int ans,n,m;
int* HorspoolTable(const char *P){
int n = strlen(P);
int* ht=new int[256]; //ht:Horspool的表,255为ASCII上限
for (int i=0;i<256;i++) ht[i]=n;//P中找不到这个字符就后移n位
for (int i=0;i<n-1/*不包括P中的尾字符*/;i++) ht[(int)P[i]]=n-i-1;
return ht;
}
void Horspool(){
int* ht=HorspoolTable(P);
for(int i=0;i<=n-m;){
int k=n-1;
for (k=m-1;k>=0&&S[i+k]==P[k];k--);
if (k==-1) ans++; //全部匹配,ans++
i=i+ht[(int)S[i+m-1]]; //否则后移对应位数
}
delete []ht;
}
int main(){
scanf("%s%s",S,P);
n=strlen(S);
m=strlen(P);
Horspool();
printf("%d\n",ans);
return 0;
}