题目链接
Leetcode.1032 字符流 Rating : 1970
题目描述
设计一个算法:接收一个字符流,并检查这些字符的后缀是否是字符串数组 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”); // 返回n 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 < = w o r d s . l e n g t h < = 2000 1 <= words.length <= 2000 1<=words.length<=2000
- 1 < = w o r d s [ i ] . l e n g t h < = 200 1 <= words[i].length <= 200 1<=words[i].length<=200
words[i]
由小写英文字母组成letter
是一个小写英文字母- 最多调用查询 4 ∗ 1 0 4 4 * 10^4 4∗104 次
解法:字典树
前缀树的结构:
struct Trie{
//判断是否为单词尾部
bool isEnd = false;
//每一个结点共有 26 个分支,因为一共有26个结点
Trie * child[26] = {nullptr};
};
我们将 words
中的所有单词 逆序 插入到 前缀树 root
中。
我们用一个全局字符串 ss
,每次查询字符 c
时,都将 c
加入到 ss
尾部。
每次都从 ss
尾部开始查询。遇到空结点就退出查询。在查询的过程中,如果当前结点 cur
的 isEnd == true
,说明 ss
的后缀匹配了字典树中的一个后缀,返回 true
。否则循环结束,返回 false
。
时间复杂度: O ( L ) O(L) O(L)
C++代码:
struct Trie{
bool isEnd = false;
Trie * child[26] = {nullptr};
};
class StreamChecker {
public:
Trie * root = new Trie();
string ss;
StreamChecker(vector<string>& words) {
for(auto s:words){
Trie * cur = root;
int n = s.size();
for(int i = n - 1;i >= 0;i--){
int idx = s[i] - 'a';
if(cur->child[idx] == nullptr) cur->child[idx] = new Trie();
cur = cur->child[idx];
}
cur->isEnd = true;
}
}
bool query(char letter) {
ss.append(1,letter);
Trie * cur = root;
int n = ss.size();
for(int i = n - 1;i >= 0;i--){
int idx = ss[i] - 'a';
if(cur->child[idx] == nullptr) break;
cur = cur->child[idx];
if(cur->isEnd) return true;
}
return false;
}
};
/**
* Your StreamChecker object will be instantiated and called as such:
* StreamChecker* obj = new StreamChecker(words);
* bool param_1 = obj->query(letter);
*/