1032. 字符流
设计一个算法:接收一个字符流,并检查这些字符的后缀是否是字符串数组 words 中的一个字符串。
例如,words = [“abc”, “xyz”] 且字符流中逐个依次加入 4 个字符 ‘a’、‘x’、‘y’ 和 ‘z’ ,你所设计的算法应当可以检测到 “axyz” 的后缀 “xyz” 与 words 中的字符串 “xyz” 匹配。
按下述要求实现 StreamChecker 类:
- StreamChecker(String[] words) :构造函数,用字符串数组 words 初始化数据结构
- boolean query(char letter):从字符流中接收一个新字符,如果字符流中的任一非空后缀能匹配 words 中的某一字符串,返回 true ;否则,返回 false。
示例:
输入: [“StreamChecker”, “query”, “query”, “query”, “query”, “query”,
“query”, “query”, “query”, “query”, “query”, “query”, “query”]
[[[“cd”, “f”, “kl”]], [“a”], [“b”], [“c”], [“d”], [“e”], [“f”], [“g”], [“h”], [“i”], [“j”], [“k”], [“l”]]
输出: [null, false, false, false, true, false, true, false, false, false, false, false, true]解释: StreamChecker streamChecker = new StreamChecker([“cd”, “f”,“kl”]);
streamChecker.query(“a”); // 返回 False
streamChecker.query(“b”); // 返回 False
streamChecker.query(“c”); // 返回 False
streamChecker.query(“d”); // 返回 True ,因为 ‘cd’ 在 words 中
streamChecker.query(“e”); // 返回 False
streamChecker.query(“f”); // 返回 True ,因为 ‘f’ 在 words 中
streamChecker.query(“g”); // 返回 False
streamChecker.query(“h”); // 返回 False
streamChecker.query(“i”); // 返回 False
streamChecker.query(“j”); // 返回 False
streamChecker.query(“k”); // 返回 False
streamChecker.query(“l”); // 返回 True ,因为 ‘kl’ 在 words 中
提示:
1 <= words.length <= 2000
1 <= words[i].length <= 200
words[i] 由小写英文字母组成
letter 是一个小写英文字母
最多调用查询 4 * 1e4 次
解析:
- 每个查询提供一个字符,如果以当前字符为结尾的字符串在words中返回true,否则返回false;
- 例如:words = [“cd”, “f”, “kl”],
- query = k,不在words中,返回false;
- query=l,发现 "kl"在words中返回true;
- query = l, 所有查询组成的字符串变为了为"kll",l,kl,kll 均不在words中,因此返回false;
- 首先,我们创建一个字典树,将words中单词全部反向插入,之所以反向插入,是因为查询的时候需要反向查找输入字符。
- 可以看出我们需要将所有输入字符全部保存为字符串(记作stream),每次查询遍历字典树,遇到 isEnd=true的节点,说明该字符为结尾的后缀能匹配 words 中的某一字符串。
代码:
class StreamChecker {
struct Node{
Node* son[26];
bool isEnd;
};
public:
string stream="";
Node* root;
// 字典树插入,反向插入字符串s(模板写法)
void insert(string& s){
Node* cur=root;
for(int i=s.size()-1;i>=0;i--){
int c = s[i]-'a';
// 节点不
if(!cur->son[c])
cur->son[c]=new Node();
cur=cur->son[c];
}
cur->isEnd=true;
}
// 搜索,反向搜索stream
bool search(){
Node* cur=root;
for(int i=stream.size()-1;i>=0;i--){
int c = stream[i]-'a';
// 如果不存在该后缀,返回false
if(!cur->son[c])
return false;
cur=cur->son[c];
// 遇到完整单词,说明后缀存在单词
if(cur->isEnd)
return true;
}
return false;
}
StreamChecker(vector<string>& words) {
root=new Node();
for(auto& a :words){
insert(a);
}
}
bool query(char letter) {
// 存储所有输入字符
stream+=letter;
return search();
}
};
/**
* Your StreamChecker object will be instantiated and called as such:
* StreamChecker* obj = new StreamChecker(words);
* bool param_1 = obj->query(letter);
*/