题目地址:
https://leetcode.com/problems/stream-of-characters/
给定一个只含英文小写字母的字符串数组 A A A,要求实现一个数据结构,其对一个字符流进行应答,对每个字符,它要应答是否从之前某个字符开始到当前字符组成的字符串在 A A A中出现过。
AC自动机模板题,直接参考https://blog.csdn.net/qq_46105170/article/details/125353461。构造自动机的时候,如果某个节点是一个字符串的结尾节点,则要将其fail指针反向的链全标记为匹配点(具体参考链接)。代码如下:
import java.util.LinkedList;
import java.util.Queue;
public class StreamChecker {
class Node {
Node[] child;
Node ne;
boolean word;
public Node() {
child = new Node[26];
}
}
Node root, cur;
void insert(String s) {
Node cur = root;
for (int i = 0; i < s.length(); i++) {
int idx = s.charAt(i) - 'a';
if (cur.child[idx] == null) {
cur.child[idx] = new Node();
}
cur = cur.child[idx];
}
cur.word = true;
}
void build() {
root.ne = root;
Queue<Node> q = new LinkedList<>();
for (int i = 0; i < 26; i++) {
if (root.child[i] != null) {
q.offer(root.child[i]);
root.child[i].ne = root;
} else {
root.child[i] = root;
}
}
while (!q.isEmpty()) {
Node cur = q.poll();
for (int i = 0; i < 26; i++) {
if (cur.child[i] != null) {
cur.child[i].ne = cur.ne.child[i];
cur.child[i].word |= cur.ne.child[i].word;
q.offer(cur.child[i]);
} else {
if (cur.ne == null) {
cur.ne = root;
}
cur.child[i] = cur.ne.child[i];
}
}
}
}
public StreamChecker(String[] words) {
root = new Node();
cur = root;
for (String w : words) {
insert(w);
}
build();
}
public boolean query(char ch) {
cur = cur.child[ch - 'a'];
return cur.word;
}
}
数据结构初始化时间复杂度 O ( ∑ i l i ) O(\sum_i l_{i}) O(∑ili),空间 O ( ∑ i l i ) O(\sum_i l_{i}) O(∑ili),每次应答时间 O ( 1 ) O(1) O(1)。