Design an algorithm that accepts a stream of characters and checks if a suffix of these characters is a string of a given array of strings words
.
For example, if words = ["abc", "xyz"]
and the stream added the four characters (one by one) 'a'
, 'x'
, 'y'
, and 'z'
, your algorithm should detect that the suffix "xyz"
of the characters "axyz"
matches "xyz"
from words
.
Implement the StreamChecker
class:
StreamChecker(String[] words)
Initializes the object with the strings arraywords
.boolean query(char letter)
Accepts a new character from the stream and returnstrue
if any non-empty suffix from the stream forms a word that is inwords
.
Example 1:
Input
["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"]]
Output
[null, false, false, false, true, false, true, false, false, false, false, false, true]
Explanation
StreamChecker streamChecker = new StreamChecker(["cd", "f", "kl"]);
streamChecker.query("a"); // return False
streamChecker.query("b"); // return False
streamChecker.query("c"); // return False
streamChecker.query("d"); // return True, because 'cd' is in the wordlist
streamChecker.query("e"); // return False
streamChecker.query("f"); // return True, because 'f' is in the wordlist
streamChecker.query("g"); // return False
streamChecker.query("h"); // return False
streamChecker.query("i"); // return False
streamChecker.query("j"); // return False
streamChecker.query("k"); // return False
streamChecker.query("l"); // return True, because 'kl' is in the wordlist
Constraints:
1 <= words.length <= 2000
1 <= words[i].length <= 2000
words[i]
consists of lowercase English letters.letter
is a lowercase English letter.- At most
4 * 104
calls will be made to query.
题目连接:https://leetcode.com/problems/stream-of-characters/
题目大意:给一个字典,和一段字符流,判断字符流中是否存在某个子串在字典中
题目分析:最暴力的做法是用字典正序建Trie,将当前匹配的树节点存下来,对于下一个字符,如果依旧匹配则继续往后,否则删除
1347ms,时间击败5%
class StreamChecker {
class TrieNode {
TrieNode[] nxt;
boolean isWord;
TrieNode() {
this.nxt = new TrieNode[26];
this.isWord = false;
}
}
private void insertTrie(TrieNode root, char[] s) {
TrieNode p = root;
for (int i = 0; i < s.length; i++) {
int idx = s[i] - 'a';
if (p.nxt[idx] == null) {
p.nxt[idx] = new TrieNode();
}
p = p.nxt[idx];
}
p.isWord = true;
}
private List<TrieNode> trieNodeList;
private TrieNode root;
public StreamChecker(String[] words) {
this.trieNodeList = new ArrayList<>();
this.root = new TrieNode();
for (int i = 0; i < words.length; i++) {
this.insertTrie(this.root, words[i].toCharArray());
}
}
public boolean query(char letter) {
int idx = letter - 'a';
List<TrieNode> tmp = new ArrayList();
boolean find = false;
for (TrieNode tn : this.trieNodeList) {
if (tn.nxt[idx] != null) {
tn = tn.nxt[idx];
tmp.add(tn);
if (tn.isWord) {
find = true;
}
}
}
TrieNode p = root;
if (p.nxt[idx] != null) {
p = p.nxt[idx];
tmp.add(p);
if (p.isWord) {
find = true;
}
}
this.trieNodeList = tmp;
return find;
}
}
/**
* Your StreamChecker object will be instantiated and called as such:
* StreamChecker obj = new StreamChecker(words);
* boolean param_1 = obj.query(letter);
*/
其实上面的做法没有充分利用到Trie的高效查找,Trie的查找效率是log的,因此可以针对每个后缀直接在trie上查,因为要查后缀,故建Trie的时候可以将单词逆序插入
128ms,时间击败30%,这题的数据不知是不是后期增强了,原来跑77ms的代码再跑也是150+ms
class StreamChecker {
class TrieNode {
TrieNode[] nxt;
boolean isWord;
TrieNode() {
this.nxt = new TrieNode[26];
this.isWord = false;
}
}
private void insertTrie(TrieNode root, char[] s) {
TrieNode p = root;
for (int i = s.length - 1; i >= 0; i--) {
int idx = s[i] - 'a';
if (p.nxt[idx] == null) {
p.nxt[idx] = new TrieNode();
}
p = p.nxt[idx];
}
p.isWord = true;
}
private StringBuilder sb;
private TrieNode root;
public StreamChecker(String[] words) {
this.sb = new StringBuilder();
this.root = new TrieNode();
for (int i = 0; i < words.length; i++) {
this.insertTrie(this.root, words[i].toCharArray());
}
}
public boolean query(char letter) {
this.sb.append(letter);
TrieNode p = this.root;
for (int i = sb.length() - 1; i >= 0; i--) {
int idx = sb.charAt(i) - 'a';
if (p.nxt[idx] != null) {
p = p.nxt[idx];
if (p.isWord) {
return true;
}
} else {
return false;
}
}
return p.isWord;
}
}
/**
* Your StreamChecker object will be instantiated and called as such:
* StreamChecker obj = new StreamChecker(words);
* boolean param_1 = obj.query(letter);
*/