package LeetCode_1032
/**
* 1032. Stream of Characters
* https://leetcode.com/problems/stream-of-characters/
* Implement the StreamChecker class as follows:
StreamChecker(words): Constructor, init the data structure with the given words.
query(letter): returns true if and only if for some k >= 1,
the last k characters queried (in order from oldest to newest,including this letter just queried) spell one of the words in the given list.
Example:
StreamChecker streamChecker = new StreamChecker(["cd","f","kl"]); // init the dictionary.
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
Note:
1. 1 <= words.length <= 2000
2. 1 <= words[i].length <= 2000
3. Words will only consist of lowercase English letters.
4. Queries will only consist of lowercase English letters.
5. The number of queries is at most 40000.
* */
/*
* Solution: Trie Tree,
* Time complexity: O(M) M is the longest length of the word,
* Space complexity: O(M*N), N is the number of word
* */
class StreamChecker(words: Array<String>) {
var root: Trie? = null
//save letter to help to check
val sb = StringBuilder()
init {
root = Trie()
for (word in words) {
addWord(word)
}
}
fun query(letter: Char): Boolean {
sb.append(letter)
var node = root
//here also check form last
for (i in sb.length - 1 downTo 0) {
if (node == null) {
continue
}
val c = sb[i]
node = node.children[c - 'a']
if (node != null && node.end) {
return true
}
}
return false
}
private fun addWord(word: String) {
var node = root
//create by reverse order, because can check from last letter
//for (ch in word) {
for (i in word.length - 1 downTo 0) {
val pos = word[i] - 'a'
if (node!!.children[pos] == null) {
node.children[pos] = Trie()
}
//set the children for current node
node = node.children[pos]
}
node!!.end = true
}
class Trie {
var end = false
var children = arrayOfNulls<Trie>(26)
}
}
/**
* Your StreamChecker object will be instantiated and called as such:
* var obj = StreamChecker(words)
* var param_1 = obj.query(letter)
*/