题意:
按下述要求实现 StreamChecker 类:
StreamChecker(words):构造函数,用给定的字词初始化数据结构。
query(letter):如果存在某些 k >= 1,
可以用查询的最后 k个字符(按从旧到新顺序,包括刚刚查询的字母)拼写出给定字词表中的某一字词时,返回 true。
否则,返回 false。
示例:
StreamChecker streamChecker = new StreamChecker(["cd","f","kl"]);
streamChecker.query('a');
streamChecker.query('b');
streamChecker.query('c');
streamChecker.query('d');
streamChecker.query('e');
streamChecker.query('f');
streamChecker.query('g');
streamChecker.query('h');
streamChecker.query('i');
streamChecker.query('j');
streamChecker.query('k');
streamChecker.query('l');
提示:
1 <= words.length <= 2000
1 <= words[i].length <= 2000
字词只包含小写英文字母。
待查项只包含小写英文字母。
待查项最多 40000 个。
解法:
发现问题就是求查询序列的某个后缀是否在字典中.
我们可以对字典中的每个串逆序建立trie,
那么对于询问,我们只需要对查询序列 逆序的从trie的根开始走,
如果走到了串结尾的标记点,说明存在这样满足条件的串,
如果走不了了或者走完了还没有标记,那么就不存在满足条件的串.
code:
struct Trie{
static const int maxm=4e4+5;
int a[maxm][26],tot;
bool val[maxm];
int last[maxm],num;
void init(){
for(int i=0;i<=tot;i++){
val[i]=0;
for(int j=0;j<26;j++){
a[i][j]=0;
}
}
num=0;
tot=0;
}
void add(string&s){
int node=0;
int len=s.size();
for(int i=len-1;i>=0;i--){
int v=s[i]-'a';
if(!a[node][v]){
a[node][v]=++tot;
}
node=a[node][v];
}
val[node]=1;
}
void insert(char&c){
last[++num]=c-'a';
}
int ask(){
int node=0;
for(int i=num;i>=1;i--){
int v=last[i];
if(!a[node][v])return 0;
node=a[node][v];
if(val[node])return 1;
}
return 0;
}
}T;
class StreamChecker {
public:
StreamChecker(vector<string>& words) {
T.init();
for(auto &i:words){
T.add(i);
}
}
bool query(char letter) {
T.insert(letter);
if(T.ask())return 1;
return 0;
}
};