PrefixTree

208. 实现 Trie (前缀树)

Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。

请你实现 Trie 类:

  • Trie() 初始化前缀树对象。
  • void insert(String word) 向前缀树中插入字符串 word
  • boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false
  • boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false

示例:

输入
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
输出
[null, null, true, false, true, null, true]

解释
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple");   // 返回 True
trie.search("app");     // 返回 False
trie.startsWith("app"); // 返回 True
trie.insert("app");
trie.search("app");     // 返回 True

提示:

  • 1 <= word.length, prefix.length <= 2000
  • wordprefix 仅由小写英文字母组成
  • insertsearchstartsWith 调用次数 总计 不超过 3 * 104

实现代码:支持可变 wordList 的 Trie

class Trie {
    private final Node root = new Node('/');
    public void insert(char[] text) {
        Node p = root;
        for (char c : text) {
            int index = c - 'a';
            if (p.children[index] == null) {
                Node newNode = new Node(c);
                p.children[index] = newNode;
            }
            p = p.children[index];
        }
        p.isEndingChar = true;
    }
    public boolean find (char[] pattern) {
        Node p = root;
        for (char c : pattern) {
            int index = c - 'a';
            if (p.children[index] == null) {
                return false;
            }
        }
        return p.isEndingChar;

    }

    private static class Node {
        public char data;
        public boolean isEndingChar = false;
        public Node[] children = new Node[26];
        public Node(char r) {
            this.data = r;
        }
    }

}

面试题 17.17. 多次搜索

给定一个较长字符串big和一个包含较短字符串的数组smalls,设计一个方法,根据smalls中的每一个较短字符串,对big进行搜索。输出smalls中的字符串在big里出现的所有位置positions,其中positions[i]smalls[i]出现的所有位置。

示例:

输入:
big = "mississippi"
smalls = ["is","ppi","hi","sis","i","ssippi"]
输出: [[1,4],[8],[],[3],[1,4,7,10],[5]]

提示:

  • 0 <= len(big) <= 1000
  • 0 <= len(smalls[i]) <= 1000
  • smalls的总字符数不会超过 100000。
  • 你可以认为smalls中没有重复字符串。
  • 所有出现的字符均为英文小写字母。

题解思想:Trie 树

class Solution {
    class TrieNode {
        String end;
        TrieNode[] next = new TrieNode[26];
    }

    class Trie {
        TrieNode root;
        public Trie(String[] words) {
            root = new TrieNode();
            for (String word : words) {
                TrieNode node = root;
                for (char r : word.toCharArray()) {
                    int i = r - 'a';
                    if (node.next[i] == null) {
                        node.next[i] = new TrieNode(); 
                    }
                    node = node.next[i];
                }
                node.end = word;
            }
        }

        public List<String> search(String str) {
            TrieNode node = root;
            List<String> res = new ArrayList<>();
            for (char c : str.toCharArray()) {
                int i = c - 'a';
                if (node.next[i] == null) {
                    break;
                }
                node = node.next[i];
                if (node.end != null) {
                    res.add(node.end);
                }
            }
            return res;
        }
    }

    public int[][] multiSearch(String big, String[] smalls) {
        Trie trie = new Trie(smalls);
        Map<String, List<Integer>> hit = new HashMap<>();
        for (int i = 0; i < big.length(); i ++) {
            List<String> matchs = trie.search(big.substring(i));
            for (String word : matchs) {
                if (!hit.containsKey(word)) {
                    hit.put(word, new ArrayList<>());
                }
                hit.get(word).add(i);
            }
        }
        int[][] res = new int[smalls.length][];
        for (int i = 0; i < smalls.length; i ++) {
            List<Integer> list = hit.get(smalls[i]);
            if (list == null) {
                res[i] = new int[0];
                continue;
            }
            int size = list.size();
            res[i] = new int[size];
            for (int j = 0; j < size; j ++) {
                res[i][j] = list.get(j);
            }
        }
        return res;
    }
}