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