shift-and,shift-or算法

shift-and,shift-or算法

维护一个字符串的集合,集合中的每个字符串既是模式串P的前缀,同时也是已读入文本的后缀。每读入一个新的文本字符,该算法即用位并行的方法更新集合。该集合用一个位掩码D=dm…d1来表示。

shift-and算法

p为模式串(长度为m),t为文本串。

​ D的第j位被置为1当且仅当p0…pj是t0…tj的后缀。当dm为1时,就表示有一个成功的匹配。

当读入下一个字符ti+1时,需要重新计算新的位掩码D’。D’的第j+1位为1的当且仅当D的第j位为1的(即p0…pj是t0…tj的后缀)并且ti+1与pi+1相等。利用位并行,D’的计算很容易在常数时间内完成。

​ shift-and算法首先构造一个表B,记录字母表中每个字符的位掩码bm…b0.如果pj = c,则掩码B[c] 的第j位被置为1,否则为0。

​ 首先置D = 0m (就是m个0的意思),对于每个新读入的文本字符ti+1,可以用如下公式对D进行更新:

​ D’ = (( D<<1 | 0m-11 ) & B[ti+1] ) ;

其中D<<1是为满足pi为1,pi+1=ti+1可由B[ti+1]的第i+1位得到,所以二者相&。我们要保证当字符ti 在p0 处出现时,D[0] 一定要等于1,而D 向左移位后最低位是0,所以要D<<1|1。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void preprocess(unsigned int B[], string T, int n)
{
    unsigned int shift=1;//从0~n-1将模式串在B中初始化
    for (int i=0; i<n; i++) {
        B[T[i]] |= shift;
        shift <<= 1;
    }
}

vector<int> and_match(string S, string T)
{
    int m=S.length(), n=T.length();
    unsigned int B[256], D=0, mask;//D初始化为00000000000
    for (int i=0; i<256; i++)
        B[i] = 0;
    preprocess(B, T, n);
    vector<int> res;

    mask  = 1 << (n - 1);//dm为1
    for (int i=0; i<m; i++) {
        D = (D << 1 | 1) & B[S[i]];
        if (D & mask)//满足说明完成一次匹配,将起始点加入
            res.push_back(i-n+1);
    }

    return res;
}

int main()
{
    string S, T;//T为模式串,S为文本串
    cin >> S >> T;
    vector<int> res=and_match(S,T);
    for (vector<int>::iterator it=res.begin(); it!=res.end(); ++it)
        cout << *it << endl;
    return 0;
}

bitset版:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<map>
#include<sstream>
#include<set>
#include<bitset>
using namespace std;
#define inf 0x3f3f3f3f
bitset<1005>B[15],D;
char s[5000005];
int n, m, x;
int main()
{
	while (scanf("%d", &n) != EOF)
	{
		for (int i = 0; i < 10; i++)
			B[i].reset();
		D.reset();
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &m);
			for (int j = 0; j < m; j++)
			{
				scanf("%d", &x);
				B[x].set(i);
			}
		}
		scanf("%s", s);
		int len = strlen(s);
		for (int i = 0; i < len; i++)
		{
			D <<= 1;
			D[0] = 1;
			D &= B[s[i] - '0'];
			if (D[n - 1] == 1) {
				char tmp = s[i + 1];
				s[i + 1] = '\0';
				puts(s + i - n + 1);
				s[i + 1] = tmp;
			}
		}
	}
	return 0;
}

shift-or算法

如果将Shift-And 中核心的“与” 运算改为“或” 运算,可以节省D<<1|1这一个附加的“或1” 运算。这正是Shift-Or 所改进的地方。
Shift-Or 与Shift-And 的唯一区别在于,在Shift-Or 中,“有效位” 是通过0(而不是1)来标识。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void preprocess(unsigned int B[], string T, int n)
{
    unsigned int shift=1;
    for (int i=0; i<n; i++) {
        B[T[i]] &= ~shift; // 有效位设为0
        shift <<= 1;
    }
}

vector<int> or_match(string S, string T)
{
    int m=S.length(), n=T.length();
    unsigned int B[256], D=~0, mask;//D初始化为11111111111111
    for (int i=0; i<256; i++)
        B[i] = ~0; // B[i]中每一位都初始化为1
    preprocess(B, T, n);
    vector<int> res;

    mask  = ~(1 << (n - 1));
    for (int i=0; i<m; i++) {
        D = (D << 1) | B[S[i]];
        if (~(D | mask))
            res.push_back(i-n+1);
    }

    return res;
}

int main()
{
    string S, T;
    cin >> S >> T;
    vector<int> res=or_match(S,T);
    for (vector<int>::iterator it=res.begin(); it!=res.end(); ++it)
        cout << *it << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值