lightoj-1427:Substring Frequency

A string is a finite sequence of symbols that are chosen from an alphabet. In this problem you are given a string Tand n queries each with a string Pi, where the strings contain lower case English alphabets only. You have to find the number of times Pi occurs as a substring of T.

Input

Input starts with an integer T (≤ 10), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 500). The next line contains the string T (1 ≤ |T| ≤ 106). Each of the next n lines contains a string Pi (1 ≤ |Pi| ≤ 500).

Output

For each case, print the case number in a single line first. Then for each string Pi, report the number of times it occurs as a substring of T in a single line.

Sample Input

Output for Sample Input

2

5

ababacbabc

aba

ba

ac

a

abc

3

lightoj

oj

light

lit

Case 1:

2

3

1

4

1

Case 2:

1

1

0



刚开始没看题目,用kmp做,超时,后来看了一下主题,知道要用AC算法。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <list>
using namespace std;

char t[1000002];

int** gt;
int* fail;
int* output;

int map[500];

char query[500][501];

int stateNum,maxStateNum;
int queryNum;

void generateGoto();
void generateFail();
void parse();

int main()
{
	int caseNum;

	maxStateNum=250;
	fail=NULL;
	output=(int*)malloc(sizeof(int)*maxStateNum);
	gt=(int**)malloc(sizeof(int*)*maxStateNum);

	for(int i=0;i<maxStateNum;++i)
		gt[i]=(int*)malloc(sizeof(int)*26);

	for(int i=0;i<maxStateNum;++i)
	{
		for(int j=0;j<26;++j)
			gt[i][j]=-1;
		fail[i]=-1;
		output[i]=-1;
	}
	

	scanf("%d",&caseNum);

	for(int i=0;i<caseNum;++i)
	{
		scanf("%d",&queryNum);
		memset(t,0,1000002);
		scanf("%s",t);
		for(int j=0;j<queryNum;++j)
		{
			memset(query[j],0,501);
			scanf("%s",query[j]);
		}
		
		stateNum=0;
		generateGoto();
		if(fail!=NULL)
			free(fail);
		fail=(int*)malloc(sizeof(int)*maxStateNum);
		for(int x=0;x<maxStateNum;++x)
			fail[x]=-1;
		generateFail();
		parse();

		printf("Case %d:\n",i+1);
		for(int p=0;p<queryNum;++p)
			printf("%d\n",output[map[p]]);
		for(int p=0;p<=stateNum;++p)
		{
			for(int q=0;q<26;++q)
				gt[p][q]=-1;
			fail[p]=output[p]=-1;
		}
	}
	return 0;
}
void generateGoto()
{
	for(int i=0;i<queryNum;++i)
	{
		int pos_gt=0;
		for(int j=0;query[i][j]!='\0';++j)
		{
			if(gt[pos_gt][query[i][j]-'a']==-1)
			{
				gt[pos_gt][query[i][j]-'a']=++stateNum;
				pos_gt=stateNum;
			}
			else
				pos_gt=gt[pos_gt][query[i][j]-'a'];
			
			if(stateNum==maxStateNum)
			{
				maxStateNum*=2;
				int** tmp=(int**)malloc(sizeof(int*)*maxStateNum);
				for(int x=0;x<maxStateNum;++x)
					tmp[x]=(int*)malloc(sizeof(int)*26);
				for(int x=0;x<stateNum;++x)
				{
					for(int y=0;y<26;++y)
						tmp[x][y]=gt[x][y];
					free(gt[x]);
				}
				free(gt);
				for(int x=stateNum;x<maxStateNum;++x)
					for(int y=0;y<26;++y)
						tmp[x][y]=-1;
				gt=tmp;

				int* ot=(int*)malloc(sizeof(int)*maxStateNum);
				for(int i=0;i<stateNum;++i)
					ot[i]=output[i];
				for(int i=stateNum;i<maxStateNum;++i)
					ot[i]=-1;
				free(output);
				output=ot;
			}
		}

		output[pos_gt]=0;
		map[i]=pos_gt;
	}
	for(int i=0;i<26;++i)
		if(gt[0][i]==-1)
			gt[0][i]=0;
}

产生goto表,每次有新的模式,从起始状态开始,若存在相应的路径,则变换到该路径的状态,若没有,则创建新的状态,并转到该状态。
void generateFail()
{
	int maxSizeOfQueue=500;
	list<int> queue;
	fail[0]=0;
	for(int i=0;i<26;++i)
		if(gt[0][i]!=-1&>[0][i]!=0)
		{
			queue.push_back(gt[0][i]);
			fail[gt[0][i]]=0;
		}

	while(!queue.empty())
	{
		int currentState=queue.front();
		queue.pop_front();
		for(int i=0;i<26;++i)
			if(gt[currentState][i]!=-1&>[currentState][i]!=0)
			{
				int st=fail[currentState];
				while(gt[st][i]==-1)
					st=fail[st];
				fail[gt[currentState][i]]=gt[st][i];
				queue.push_back(gt[currentState][i]);
			}
	}
}

从0状态开始,0状态不会失败,1状态失败总是到0。然后层次遍历,对于fail[r],查看他的前一个状态p,p和r之间有‘a’边,若fail[p]存在‘a’的边,则fail[r]=goto(fail[p],a)。若没有,则检查fail[fail[p]],直到存在.0状态不会失败,确保迭代终止。

void parse()
{
	int pos_gt=0;
	for(int i=0;t[i]!='\0';++i)
	{
		while(gt[pos_gt][t[i]-'a']==-1)
			pos_gt=fail[pos_gt];
		pos_gt=gt[pos_gt][t[i]-'a'];
		int tgt=pos_gt;
		while(tgt!=0)
		{
			if(output[tgt]!=-1)
				++output[tgt];
			tgt=fail[tgt];
		}
	}
}

最后遍历主串。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值