题目描述
Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补全和拼写检查。
请你实现 Trie 类:
Trie() 初始化前缀树对象。
void insert(String word) 向前缀树中插入字符串 word 。
boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。
题目分析
前缀树每个结点是一个字符,结点内有结束标记(表示有单词在这里结束),同时可以指向后续其他字符。复用的是从根结点出发的路径,而不是字符。
从根结点出发,字符串增加和查找的时间复杂度为 O(字符串长度)。
例如:
1. 插入hello:root → h → e → l → l → o (结束)
2. 插入help:root → h → e → l 是共享的,在 l 之后分叉出新分支 p(结束)
Java
public class Trie {
private static class Node {
public char ch;
public boolean isEnd = false;
private HashMap<Character, Node> next = new HashMap<>();
public Node(char ch) {
this.ch = ch;
}
private Node findNext(char ch) {
return next.get(ch);
}
private Node addNext(char ch) {
if (next.containsKey(ch)) {
return next.get(ch);
}
Node node = new Node(ch);
next.put(ch, node);
return node;
}
}
private Node root = new Node('0');
public Trie() {
}
public void insert(String word) {
Node cur = root;
for (int i = 0; i < word.length(); i++) {
cur = cur.addNext(word.charAt(i));
}
cur.isEnd = true;
}
public boolean search(String word) {
Node cur = root;
for (int i = 0; i < word.length(); i++) {
cur = cur.findNext(word.charAt(i));
if (cur == null) {
return false;
}
}
return cur.isEnd;
}
public boolean startsWith(String prefix) {
Node cur = root;
for (int i = 0; i < prefix.length(); i++) {
cur = cur.findNext(prefix.charAt(i));
if (cur == null) {
return false;
}
}
return true;
}
}
Kotlin
class Trie {
private class Node(val ch: Char, var isEnd: Boolean = false) {
val next = HashMap<Char, Node>()
fun addNext(ch: Char): Node {
return findNext(ch) ?: Node(ch).also {
next[ch] = it
}
}
fun findNext(ch: Char): Node? {
return next[ch]
}
}
private val root = Node('0')
fun insert(word: String) {
var cur = root
for (ch in word) {
cur = cur.addNext(ch)
}
cur.isEnd = true
}
fun search(word: String): Boolean {
var cur = root
for (ch in word) {
cur = cur.findNext(ch) ?: return false
}
return cur.isEnd
}
fun startsWith(prefix: String): Boolean {
var cur = root
for (ch in prefix) {
cur = cur.findNext(ch) ?: return false
}
return true
}
}