• 序列自动机


    是看了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;
    }
    

      

  • 相关阅读:
    jQuery--.wrap()方法
    ECharts学习(4)--仪表盘
    ECharts学习(3)--toolbox(工具栏)
    jQuery之核心API
    STM32片上Flash内存映射、页面大小、寄存器映射
    typedef struct bit0 : 1
    ***WARNING L15: MULTIPLE CALL TO SEGMENT
    C/C++ 打印文件名、行号、函数名的方法
    ISP与IAP的区别
    sprintf函数 %6.2f
  • 原文地址:https://www.cnblogs.com/yuanweidao/p/10752497.html
Copyright © 2020-2023  润新知