更高效的字符串匹配算法——shift-and

在接触这个算法之前,一直觉得kmp巧夺天工,利用next数组的递推,实现对于模式串任一子串最大相同前后缀的找寻,继而在匹配目标串的过程中,一旦遇到失配情况,可以令 匹配起始下标 进行合理范围内最大的跳跃,从而将匹配整体复杂度从O(nm)降为O(m+n)。

a b c a b c ........

a b c a b    可从目标串第二个 a 处开始匹配

shift-and算法与其思路基本相同,同样是找寻最大匹配长度,只不过它的实现基于更为方便快捷的位运算,算法的实现需要用到这个头文件,点击查看其功能用法。bitset类实现了通过类似数组下标的方式访问对象的每一个bit位,极大方便了对于该对象储存信息的提取。

算法大致思路:

1.根据模式串每位的字符建立字符表,如 a 对应的(bitset<5>)"00101",表示在模式串的1,3位上可以是字符a。

2.初始化储存结果的bitset对象 D 为"00000",表示没有一个字符成功匹配,(即没有一个字符既是完整模式串的前缀,又是当前目标串的后缀,通俗来讲就是,失配后起始位要老老实实挪到下一位,跳不成)。之后则不断从目标串中读入字符,并套用公式

                                                               D=(D<<1|1)&B[s[i]];

  表示将原结果左移一位,将[1]位置为1,表示对于新的一位匹配的期望,如果B[s[i]]第一位刚好也为1,则D串中即可更新。

  该&操作的意义是:(D<<1|1)试图将所有匹配位均向左增加一位,如果新加入的字符模式串中该位出现过,则匹配串升级成功。

3.时刻检查,如果D中n位为1,则证明出现一组匹配结果。

 

 

下面展示样题:

2016 大连ICPC B

数字串匹配,模式串(长度小于1000)中的每个位上,均有若干个可选项,给定一个较长的目标串(长度小于5*1e6),输出所有匹配结果。

 

#include
#include
#include
#include

using namespace std;

bitset<1001> b[10],ans;
char s[5000005];
int n,len;

int main()
{
    cin>>n;
    char ch;
    for(int i=1; i<=n; i++)
    {
        int m;
        scanf("%d",&m);
        for(int j=0; j

 

压着超时的线通过,通过这道题发现直接用puts比一个一个putchar快不少。

你可能感兴趣的:(字符串)