Stream of Characters

hard trie reversed trie suffix matching

Problem

Design an algorithm that accepts a stream of characters and checks, after each new character, whether some suffix of the characters received so far spells a word from a given dictionary. Implement query(letter) which returns true if the letters seen so far end with any dictionary word.

Inputwords = ["cd", "f", "kl"], queries = "abcd"
Output[false, false, false, true]
After 'd' the stream ends with "cd", a dictionary word, so the fourth query returns true.

class StreamChecker:
    def __init__(self, words):
        self.trie = {}
        self.stream = []
        for w in words:
            node = self.trie
            for c in reversed(w):
                node = node.setdefault(c, {})
            node["$"] = True

    def query(self, letter):
        self.stream.append(letter)
        node = self.trie
        for c in reversed(self.stream):
            if c not in node:
                return False
            node = node[c]
            if "$" in node:
                return True
        return False
class StreamChecker {
  constructor(words) {
    this.trie = {};
    this.stream = [];
    for (const w of words) {
      let node = this.trie;
      for (let i = w.length - 1; i >= 0; i--) {
        const c = w[i];
        node = node[c] || (node[c] = {});
      }
      node["$"] = true;
    }
  }

  query(letter) {
    this.stream.push(letter);
    let node = this.trie;
    for (let i = this.stream.length - 1; i >= 0; i--) {
      const c = this.stream[i];
      if (!(c in node)) return false;
      node = node[c];
      if (node["$"]) return true;
    }
    return false;
  }
}
class StreamChecker {
    private Map<Character, Object> trie = new HashMap<>();
    private StringBuilder stream = new StringBuilder();

    public StreamChecker(String[] words) {
        for (String w : words) {
            Map<Character, Object> node = trie;
            for (int i = w.length() - 1; i >= 0; i--) {
                char c = w.charAt(i);
                node = (Map<Character, Object>) node.computeIfAbsent(c, k -> new HashMap<>());
            }
            node.put('$', Boolean.TRUE);
        }
    }

    public boolean query(char letter) {
        stream.append(letter);
        Map<Character, Object> node = trie;
        for (int i = stream.length() - 1; i >= 0; i--) {
            char c = stream.charAt(i);
            if (!node.containsKey(c)) return false;
            node = (Map<Character, Object>) node.get(c);
            if (node.containsKey('$')) return true;
        }
        return false;
    }
}
struct Node { unordered_map<char, Node*> next; bool end = false; };

class StreamChecker {
    Node* trie = new Node();
    string stream;
public:
    StreamChecker(vector<string>& words) {
        for (auto& w : words) {
            Node* node = trie;
            for (int i = (int)w.size() - 1; i >= 0; i--) {
                char c = w[i];
                if (!node->next.count(c)) node->next[c] = new Node();
                node = node->next[c];
            }
            node->end = true;
        }
    }

    bool query(char letter) {
        stream.push_back(letter);
        Node* node = trie;
        for (int i = (int)stream.size() - 1; i >= 0; i--) {
            char c = stream[i];
            if (!node->next.count(c)) return false;
            node = node->next[c];
            if (node->end) return true;
        }
        return false;
    }
};
Time: O(L) per query Space: O(Σ|word|)