Decode Algorithms & LeetCode
  • Decode Algorithms & LeetCode
  • G家练习
  • Array
    • Two Sum
    • Two Pointers
    • PrefixSum
    • Matrix
    • Interval & Sweepline
    • Sort
    • Iterator
    • Segment Tree
  • Binary Search
    • 教学
    • Binary Search on Matrix
    • Binary Search To Find An Answer
  • String
    • Parenthesis
    • Sliding Window
    • Trie
  • LinkedList
  • Tree
    • Level Order Traversal
    • BST or Inorder
    • Construst Tree
  • Stack
  • Heap
  • Greedy
  • BFS
  • DFS
    • DFS on String
    • Backtracking
    • DFS+Memo
  • Graph
    • Union Find
    • Topological Sort
    • Dijkstra
    • Bipartite Graph
  • Dynamic Programing
    • DP on String
    • Knapsack Problem
  • Design
    • Concurrency
  • Math
  • Bit Manipulation
Powered by GitBook
On this page

Was this helpful?

  1. String

Trie

PreviousSliding WindowNextLinkedList

Last updated 4 years ago

Was this helpful?

    /** Initialize your data structure here. */
    TrieNode root;
    public Trie() {
        root = new TrieNode();
    }
    
    /** Inserts a word into the trie. */
    public void insert(String word) {
        TrieNode curt = root;
        for (char c : word.toCharArray()) {
            int id = c - 'a';
            if (curt.children[id] == null) curt.children[id] = new TrieNode();
            curt = curt.children[id];
        }
        curt.isWord = true;    
    }
    
    /** Returns if the word is in the trie. */
    public boolean search(String word) {
        return find(word.toCharArray(), root, false);
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    public boolean startsWith(String prefix) {
        return find(prefix.toCharArray(), root, true);
    }
    
    private boolean find(char[] chars, TrieNode curt, boolean prefix) {
        for (char c : chars) {
            int id = c - 'a';
            if (curt.children[id] == null) return false;
            curt = curt.children[id];
        }
        if (prefix) return true;
        return curt.isWord;
    }
    
    class TrieNode {
        TrieNode[] children;
        boolean isWord = false;
        TrieNode() {
            this.children = new TrieNode[26];
        }
    }
class TrieNode:
    def __init__(self):
        self.children = {}
        self.isEnd = False
        
class Trie:
    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.root = TrieNode()


    def insert(self, word: str) -> None:
        """
        Inserts a word into the trie.
        """
        curt = self.root
        for char in word:
            if char not in curt.children:
                curt.children[char] = TrieNode()
            curt = curt.children[char]
        curt.isEnd = True


    def search(self, word: str) -> bool:
        """
        Returns if the word is in the trie.
        """
        curt = self.root
        for char in word:
            if char not in curt.children:
                return False
            curt = curt.children[char]
        return curt.isEnd


    def startsWith(self, prefix: str) -> bool:
        """
        Returns if there is any word in the trie that starts with the given prefix.
        """
        curt = self.root
        for char in prefix:
            if char not in curt.children:
                return False
            curt = curt.children[char]
        return True
  class TrieNode {
    TrieNode[] children = new TrieNode[26];
    boolean WordEnd;

    public TrieNode() {
      for (TrieNode node : children) {
        node = null;
      }
      WordEnd = false;
    }
  }

  /** Initialize your data structure here. */
  TrieNode root;
  public WordDictionary() {
    root = new TrieNode();
  }

  /** Adds a word into the data structure. */
  public void addWord(String word) {
    addWord(word, root);
  }

  private void addWord(String word, TrieNode root) {
    TrieNode curt = root;
    for (char c : word.toCharArray()) {
      int index = c - 'a';
      if (curt.children[index] == null) {
        curt.children[index] = new TrieNode();
      }
      curt = curt.children[index];
    }
    curt.WordEnd = true;
  }

  /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */
  public boolean search(String word) {
    return search(word.toCharArray(), 0, root);
  }

  private boolean search(char[] chars, int index, TrieNode curt) {
    if (index == chars.length) return curt.WordEnd;
    if (chars[index] == '.') {
        for (TrieNode child : curt.children) {
            if (child == null) continue;
            if (search(chars, index + 1, child)) return true;
        }  
    } else {
        if (curt.children[chars[index] - 'a'] == null) return false;
        return search(chars, index + 1, curt.children[chars[index] - 'a']);
    }
    return false;
  }
class TrieNode:
    def __init__(self):
        self.children = {}
        self.isEnd = False
        
class WordDictionary:

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.root = TrieNode()

    def addWord(self, word: str) -> None:
        """
        Adds a word into the data structure.
        """
        curt = self.root
        for char in word:
            if char not in curt.children:
                curt.children[char] = TrieNode()
            curt = curt.children[char]
        curt.isEnd = True
        

    def search(self, word: str) -> bool:
        """
        Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter.
        """
        return self.dfs(0, word, self.root)
    
    def dfs(self, i, word, curt):
        if i == len(word):
            return curt.isEnd
        if word[i] != '.':
            if word[i] not in curt.children:
                return False
            return self.dfs(i + 1, word, curt.children[word[i]])
        else:
            for key in curt.children:
                if self.dfs(i + 1, word, curt.children[key]):
                    return True
        return False

Build Trie and store index of the string in folder, the index has default value of -1.

BFS to find all parents, offer Tire root to the queue. While queue is not empty, pop nodes with index != -1, which means it is a parent folder. Check if it is children is not null and not 26 (which represent "/"), then it is another valid answer. For example, "/a/b/ca" is not a subfolder of "/a/b/c"

    class TrieNode {
        TrieNode[] children;
        int index;
        TrieNode() {
            children = new TrieNode[27];
            index = -1;
        }
    }
    
    TrieNode root;
    public List<String> removeSubfolders(String[] folder) {
        root = new TrieNode();
        for (int i = 0; i < folder.length; i++) {
            TrieNode curt = root;
            buildTrie(curt, folder[i], i);
        }
        List<String> result = new ArrayList<>();
        BFS(root, folder, result);
        return result;
    }
    
    private void BFS(TrieNode root, String[] folder, List<String> res) {
        Queue<TrieNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TrieNode curt = queue.poll();
            if (curt.index != -1) {
                res.add(folder[curt.index]);
            } 
            for (int i = 0; i < 27; i++) {
                if (curt.children[i] != null 
                    && !(i == 26 && curt.index != -1)) {
                    queue.offer(curt.children[i]);
                }
            }
        }
    }
    
    private void buildTrie(TrieNode curt, String s, int index) {
        for (char c : s.toCharArray()) {
            int id = c == '/' ? 26 : c - 'a';
            if (curt.children[id] == null) {
                curt.children[id] = new TrieNode();
            }
            curt = curt.children[id];
        }
        curt.index = index;
    }

When building Trie, add to the word to the end of Trie node. DFS search on Trie in 4 directions. Set the visited grid to '#' to eliminate revisit, flip it back as DFS completes.

T: O(m * n * 4 * 3 ^ (L - 1)) S : O(len*k)

    class TrieNode {
        TrieNode[] children;
        String word;
        TrieNode() {
            children = new TrieNode[26];
        }
    }

    TrieNode root = new TrieNode();
    public List<String> findWords(char[][] board, String[] words) {
        if (board == null || board.length == 0 || board[0].length == 0 || words.length == 0) {
            return new ArrayList<>();
        }
        for (String w: words) {
            buildTrie(w, root);
        }
        List<String> res = new ArrayList<>();
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                dfs(board, i, j, root, res);
            }
        }
        return res;
    }

    int[][] dirs = {{1,0}, {-1, 0}, {0,1}, {0,-1}};
    private void dfs(char[][] board, int x, int y, TrieNode curt, List<String> res) {
        if (!inbound(board, x, y) || board[x][y] == '#') return;
        int index = board[x][y] - 'a';
        curt = curt.children[index];
        if (curt == null) return;
        if (curt.word != null) {
            res.add(curt.word);
            curt.word = null;
        }
        char c = board[x][y];
        for (int[] d : dirs) {
            board[x][y] = '#';
            dfs(board, x + d[0], y + d[1], curt, res);
            board[x][y] = c; 
        }
    }

    private void buildTrie(String w, TrieNode root) {
        TrieNode curt = root;
        for (char c : w.toCharArray()) {
            int index = c - 'a';
            if (curt.children[index] == null) curt.children[index] = new TrieNode();
            curt = curt.children[index];
        }
        curt.word = w;
    }

    private boolean inbound(char[][] board, int x, int y) {
        return x >= 0 && x < board.length && y >= 0 && y < board[0].length;
    }

Added 3 sorted suggestion words to the TrieNode. Traverse Trie by searchWord, add empty arrays if reached null nodes.

    TrieNode root;
    public List<List<String>> suggestedProducts(String[] products, String searchWord) {
        root = new TrieNode();
        Arrays.sort(products);
        for (String product : products) {
            buildTrie(root, product);
        }
        List<List<String>> results = new ArrayList<>();
        char[] chars = searchWord.toCharArray();
        int i = 0; 
        while (i < chars.length) {
            int index = chars[i] - 'a';
            if (root.children[index] == null) {
                while (i++ < chars.length) {
                    results.add(new ArrayList<>());
                }
            } else {
                results.add(new ArrayList<>(root.children[index].words));
                root = root.children[index];
            }
            i++;
        }
        return results;
    }
    
    private void buildTrie(TrieNode curt, String w) {
        char[] arr = w.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            int index = arr[i] - 'a';
            if (curt.children[index] == null) {
                curt.children[index] = new TrieNode();
            }
            curt = curt.children[index];
            if (curt.words.size() < 3) {
                curt.words.add(w);
            }
        }
        curt.isEnd = true;
    }
    
    class TrieNode {
        TrieNode[] children;
        List<String> words;
        boolean isEnd;
        TrieNode() {
            children = new TrieNode[26];
            words = new ArrayList<>();
        }
    }

Construct Trie Tree with words provided. When search, count the words which is already found and keep finding the next word from root, return true when total words find is >= 2.

T: build Trie: O(n * k) , search: O(n* k) S: O(n * k)

    public List<String> findAllConcatenatedWordsInADict(String[] words) {
        List<String> res = new ArrayList<String>();
        if (words == null || words.length == 0) {
            return res;
        }
        TrieNode root = new TrieNode();
        for (String w : words) {
            addWord(w, root);
        }
        for (String w : words) {
            if (search(w.toCharArray(), 0, root, 0)) {
                res.add(w);
            }
        }
        return res;
    }

    public boolean search(char[] chars, int index, TrieNode root, int count) { 
        if (index == chars.length) return count >= 2;
        TrieNode curt = root;
        for (int i = index; i < chars.length; i++) {
            int id = chars[i] - 'a';
            if (curt.children[id] == null) return false;
            curt = curt.children[id];
            if (curt.isEnd && search(chars, i + 1, root, count + 1)) {
                return true;
            } 
        }
        return false;
    }

    public void addWord(String str, TrieNode root) {
        char[] chars = str.toCharArray();
        TrieNode cur = root;
        for (char c : chars) {
            if (cur.children[c - 'a'] == null) {
                cur.children[c - 'a'] = new TrieNode();
            }
            cur = cur.children[c - 'a'];
        }
        cur.isEnd = true;
    }

    class TrieNode {
        TrieNode[] children;
        boolean isEnd;
        public TrieNode() {
            children = new TrieNode[26];
        }
    }

Build Trie with words on the corresponding node. Simultaneously search the Trie and the board to find the word on the node, mark the grid as '#' to indicate visited, erase the word after added to the result. (this is because you only want to find one word if there are duplicates on the grid) Check if the x, y coordinates are out of bound or visited. Add word to the result.

T: O(M(4⋅3 L−1)), where MM is the number of cells in the board and LL is the maximum length of words.

    class TrieNode {
        TrieNode[] children;
        String word;
        TrieNode() {
            children = new TrieNode[26];
        }
    }

    TrieNode root = new TrieNode();
    public List<String> findWords(char[][] board, String[] words) {
        if (board == null || board.length == 0 || board[0].length == 0 || words.length == 0) {
            return new ArrayList<>();
        }
        for (String w: words) {
            buildTrie(w, root);
        }
        List<String> res = new ArrayList<>();
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                dfs(board, i, j, root, res);
            }
        }
        return res;
    }

    int[][] dirs = {{1,0}, {-1, 0}, {0,1}, {0,-1}};
    private void dfs(char[][] board, int x, int y, TrieNode curt, List<String> res) {
        if (!inbound(board, x, y) || board[x][y] == '#') return;
        int index = board[x][y] - 'a';
        if (curt.children[index] == null) return;
        curt = curt.children[index];
        if (curt.word != null) {
            res.add(curt.word);
            curt.word = null;
        }
        for (int[] dir : dirs) {
            char c = board[x][y];
            board[x][y] = '#';
            dfs(board, x + dir[0], y + dir[1], curt, res);
            board[x][y] = c;
        }
    }

    private void buildTrie(String w, TrieNode root) {
        TrieNode curt = root;
        for (char c : w.toCharArray()) {
            int index = c - 'a';
            if (curt.children[index] == null) curt.children[index] = new TrieNode();
            curt = curt.children[index];
        }
        curt.word = w;
    }

    private boolean inbound(char[][] board, int x, int y) {
        return x >= 0 && x < board.length && y >= 0 && y < board[0].length;
    }

At each TrieNode, set children map and a separate map to count the corresponding word and frequency. Write a function List<String> getTop3() and use max heap to produce the top 3 words in each node.

AutocompleteSystem() takes O(k*l) time. We need to iterate over l sentences each of average length k, to create the trie for the given set of sentences. input() takes O(p+q+m *log m)time. Here, p refers to the length of the sentence

    TrieNode root;
    String prefix;
    public AutocompleteSystem(String[] sentences, int[] times) {
        root = new TrieNode();
        prefix = "";
        for (int i = 0; i < sentences.length; i++) {
            buildTrie(root, sentences[i], times[i]);
        }
    }

    private void buildTrie(TrieNode curt, String s, int time) {
        for (char c : s.toCharArray()) {
            TrieNode next = curt.children.get(c);
            if (next == null) {
                next = new TrieNode();
                curt.children.put(c, next);
            }
            curt = next;
            curt.count.put(s, curt.count.getOrDefault(s, 0) + time);
        }
        curt.isEnd = true;
    }

    public List<String> input(char c) {
        if (c == '#') { // add prefix to Trie and reset prefix
            buildTrie(root, prefix, 1);
            prefix = "";
            return new ArrayList<>();
        }
        prefix = prefix + c;
        TrieNode curt = root;
        for (char cc: prefix.toCharArray()) {
            if (curt.children.get(cc) == null) return new ArrayList<>();
            curt = curt.children.get(cc);
        }
        return curt.getTop3();
    }

    class TrieNode {
        Map<Character, TrieNode> children;
        Map<String, Integer> count;
        boolean isEnd;
        TrieNode() {
            this.children = new HashMap<>();
            this.count = new HashMap<>();
            this.isEnd = false;
        }
        
        public List<String> getTop3() {
            List<String> res = new ArrayList<>();
            PriorityQueue<Map.Entry<String, Integer>> pq
                    = new PriorityQueue<>(new Comparator<Map.Entry<String, Integer>>() {
                @Override
                public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                    if (o1.getValue() == o2.getValue()) {
                        return o1.getKey().compareTo(o2.getKey());
                    }
                    return o2.getValue() - o1.getValue();
                }
            });

            pq.addAll(count.entrySet());
            for (int i = 0; i < 3 && !pq.isEmpty(); i++) {
                res.add(pq.poll().getKey());
            }
            return res;
        }
    }
TrieNode root;
StringBuilder sb;
public StreamChecker(String[] words) {
    root = new TrieNode();
    for (String w : words) {
        add(w.toCharArray());
    }
    sb = new StringBuilder();
}

public boolean query(char letter) {
    sb.append(letter);
    TrieNode curt = root;
    for (int i = sb.length() - 1; i >= 0; i--) {
        int index = sb.charAt(i) - 'a';
        if (curt.children[index] == null) return false;
        curt = curt.children[index];
        if (curt != null && curt.isWord) return true;
    }
    return false;
}

class TrieNode {
    TrieNode[] children;
    boolean isWord;
    TrieNode() {
        children = new TrieNode[26];
        isWord = false;
    }
}

private void add(char[] chars) {
    TrieNode curt = root;
    for (int i = chars.length - 1; i >= 0; i--) {
        int id = chars[i] - 'a';
        if (curt.children[id] == null) curt.children[id] = new TrieNode();
        curt = curt.children[id];
    }
    curt.isWord = true;
}

Solution1: Build & Search all words in Trie (Build: O(L), Search (n * L * 26))

Solution2: Rolling Character Matching (O(S + W * L))

public int numMatchingSubseq(String S, String[] words) {
    TrieNode root = new TrieNode();
    buildTrie(S, root);
    int count = 0;
    Map<String, Integer> map = new HashMap<>();
    for (String w : words) {
        map.put(w, map.getOrDefault(w, 0) + 1);
    }
    for (String w : map.keySet()) {
        if (dfs(root, w.toCharArray(), 0)) {
            count += map.get(w);
        }
    }
    return count;
}

private boolean dfs(TrieNode curt, char[] chars, int i) {
    if (i == chars.length) {
        return true;
    }
    int index = chars[i] - 'a';
    if (curt.children[index] != null) {
        return dfs(curt.children[index], chars, i + 1);
    } else {
        for (int k = 0; k < 26; k++) {
            if (curt.children[k] != null && dfs(curt.children[k], chars, i)) {
                return true;
            }
        }
    }
    return false;
}

private void buildTrie(String s, TrieNode curt) {
    for (int i = 0; i < s.length(); i++) {
        int index = s.charAt(i) - 'a';
        if (curt.children[index] == null) {
            curt.children[index] = new TrieNode();
        }
        curt = curt.children[index];
    }
    curt.isEnd = true;
}

class TrieNode {
    TrieNode[] children;
    boolean isEnd;
    TrieNode() {
        children = new TrieNode[26];
    }
}
class Item {
    String word;
    int index;
    public Item (String s, int i) {
        word = s;
        index = i;
    }
}
public int numMatchingSubseq(String S, String[] words) {
    Queue<Item>[] dict = new Queue[26];
    for (int i = 0; i < dict.length; i++) {
        dict[i] = new LinkedList<>();
    }

    for (String word :words) {
        if (word.length() > 0) {
            dict[word.charAt(0) - 'a'].add(new Item(word, 0));
        }
    }

    int count = 0;
    for (char c : S.toCharArray()) {
        Queue<Item> queue = dict[c - 'a'];
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            Item top = queue.poll();
            top.index++;
            if (top.index == top.word.length()) {
                count++;
            } else {
                dict[top.word.charAt(top.index) - 'a'].add(top);
            }
        }
    }

    return count;
}

208. Implement Trie (Prefix Tree)
211. Add and Search Word - Data structure design
1233. Remove Sub-Folders from the Filesystem
212. Word Search II
1268. Search Suggestions System
472. Concatenated Words
212. Word Search II
642. Design Search Autocomplete System
1032. Stream of Characters
792. Number of Matching Subsequences
527. Word Abbreviation