简述
序列自动机是一个能快速判断一个串t是否为另一个串s的子序列的算法。对于串s构造序列自动机,本质上就是预处理出一个nxt[][]数组,nxt[i][j]代表从第i个位置开始,字符j出现的第一个位置的下一个位置。
代码详解
构造
复杂度O(lens)
对于nxt数组的构造本质上就是一个dp的过程,len位置就是最后一个位置+1,所以我们设置一个末边界为inf,往前递推对于之后的每个位置该位置的字符的nxt值就是i+1,其他字符就是nxt[i+1]的值。
void init(char *s){ int len=strlen(s); for(int i=0;i<26;i++) nxt[len][i]=inf; for(int i=len-1;i>=0;i--){ for(int j=0;j<26;j++){ nxt[i][j]=nxt[i+1][j]; } nxt[i][s[i]-'a']=i; } }
查询
复杂度O(lent)
对于串t,我们可以利用nxt数组,pos指针初始化为0,pos就是开始查找的下标,每次令pos=nxt[pos][当前字符],也就是匹配字符的后一个位置=下一个开始找的位置,当pos=inf时证明在pos位置开始后面没有所需字符了,所以不是子序列。
bool find(char *t){ int len=strlen(t); int pos=-1; for(int i=0;i<len;i++){ pos=nxt[pos+1][t[i]-'a']; if(pos==inf) return 0; } return 1; }
模板
void init(char *s){ int len=strlen(s); for(int i=0;i<26;i++) nxt[len][i]=inf; for(int i=len-1;i>=0;i--){ for(int j=0;j<26;j++){ nxt[i][j]=nxt[i+1][j]; } nxt[i][s[i]-'a']=i; } } bool find(char *t){ int len=strlen(t); int pos=-1; for(int i=0;i<len;i++){ pos=nxt[pos+1][t[i]-'a']; if(pos==inf) return 0; } return 1; }