序列自动机

是看了LZL大佬的博客才学到的一种新查找方式,感觉还挺好用的.就记录下来

作用是:在一个文本串中查找子序列是否存在或者组成字符的最近位置

这就是不能用kmp算法的地方, 因为kmp算法适用于 模式串是由文本串中连续的若干字符组成 的查找

 

序列自动机里用到了next二维数组, next[][],储存着在i位置之后最近的j字符的位置在哪儿.

例如next[5][2] = x: 首先2是由 'c' - 'a'得到的,所以代表着c字符在5位置之后的最近位置x

需要注意的一点是文本串需要预留出一个0位置的空间出来作为起点,所以输入变为

 

scanf("%s", str + 1);//这样就预留出了0位置

  获得next数组的操作以及注解

void getnext()
{
	memset(next, 0, sizeof(next));//初始化为0代表i位置之后没有该字符 
	int len = strlen(str + 1);//长度相应的从1下标开始 
	for(int i = len; i >= 1; i --)
	{
		for(int j = 0; j < 26; j ++)
		{
			next[i - 1][j] = next[i][j];//str i-1位置继承str i位置的离其它字符最近的位置是第几个
		}
		next[i - 1][str[i] - 'a'] = i;// str i-1位置离str[i]字符的最近位置变为第i个. 
	}
}

  

查找部分代码

                int flag = 1;
		scanf("%s", s);
		int len = strlen(s);//模式串长度 
		int now = 0;//起点0记录了所有字符的最近位置,从0开始找 
		for(int i = 0; i < len; i ++)
		{
			now = next[now][s[i] - 'a'];
			if(!now)//如果查到某个字符结果为0说明now位置之后不再有该字符,标记跳出 
			{
				flag = 0;
				break;
			}
		}
		if(flag)
			printf("Yes\n");
		else
			printf("No\n");

  例题在此:https://ac.nowcoder.com/acm/contest/392/J

AC完整代码

#include<stdio.h>
#include<string.h>

char str[1000000 + 10];
char s[1000000 + 10];
int next[1000000 + 10][30];

void getnext()
{
	memset(next, 0, sizeof(next));//初始化为0代表i位置之后没有该字符 
	int len = strlen(str + 1);//长度相应的从1下标开始 
	for(int i = len; i >= 1; i --)
	{
		for(int j = 0; j < 26; j ++)
		{
			next[i - 1][j] = next[i][j];//str i-1位置继承str i位置的离其它字符最近的位置是第几个
		}
		next[i - 1][str[i] - 'a'] = i;// str i-1位置离str[i]字符的最近位置变为第i个. 
	}
}

int main()
{
	scanf("%s", str + 1);
	getnext(); //获得序列自动机的next数组 
	int T;
	scanf("%d", &T);
	getchar();
	while(T --)
	{
		int flag = 1;
		scanf("%s", s);
		int len = strlen(s);//模式串长度 
		int now = 0;//起点0记录了所有字符的最近位置,从0开始找 
		for(int i = 0; i < len; i ++)
		{
			now = next[now][s[i] - 'a'];
			if(!now)//如果查到某个字符结果为0说明now位置之后不再有该字符,标记跳出 
			{
				flag = 0;
				break;
			}
		}
		if(flag)
			printf("Yes\n");
		else
			printf("No\n");
	} 
	return 0;
}

  

posted @ 2019-04-22 19:44  缘未到  阅读(836)  评论(0编辑  收藏  举报