题目描述
实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。
示例:
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
说明:
你可以假设所有的输入都是由小写字母 a-z 构成的。
保证所有输入均为非空字符串。
题解过程
思路
- 先定义Trienode数据结构
- 三个private初始定义
- Trienode[] links
- R=26
- isEnd
- 一个构造函数
- 创建前缀树
- 五大方法
- 节点是否存在 containsKey()
- 获取节点 get()
- 放置节点 put()
- 设置终点 setEnd()
- 查看是否为终点 isEnd()
- 三个private初始定义
- 写Trie类
- 初始化root
- 构造 Trie()
- insert()
- 新建node->获取字符->判断是否存在该字符
- 不存在->放置字符,再获取字符所在节点
- (存在)获取字符所在节点
- 循环结束,设置终点
- 新建node->获取字符->判断是否存在该字符
- search()
- 调用searchPrefix()
- 新建node->获取字符->判断是否存在该字符
- 存在,获取字符
- 否则(不存在),置null,
- 返回node
- 循环结束,返回node
- 新建node->获取字符->判断是否存在该字符
- 判断不为空且在终点
- 调用searchPrefix()
- startsWith()
- 调用searchPrefix()
- 判断不为空
完整代码
//数据结构
class TrieNode {
// R links to node children
//前缀树节点数组
private TrieNode[] links;
//每个节点由26个字符
private final int R = 26;
//判断是否到达结尾
private boolean isEnd;
//新建前缀树节点
public TrieNode() {
//别忘了节点数R
links = new TrieNode[R];
}
//是否包含该字符
public boolean containsKey(char ch) {
return links[ch -'a'] != null;
}
//获取该字符
public TrieNode get(char ch) {
return links[ch -'a'];
}
//放置该节点进入links中
public void put(char ch, TrieNode node) {
links[ch -'a'] = node;
}
//若到达终点,将isEnd置true
public void setEnd() {
isEnd = true;
}
//判断是否已经到终点
public boolean isEnd() {
return isEnd;
}
}
//前缀树,又称字典树,单词查找树
class Trie {
//获取根节点。
private TrieNode root;
//初始化根节点
public Trie() {
root = new TrieNode();
}
// Inserts a word into the trie.
public void insert(String word) {
//新建node为root
TrieNode node = root;
for (int i = 0; i < word.length(); i++) {
//当前字符
char currentChar = word.charAt(i);
//若不存在,则放置
if (!node.containsKey(currentChar)) {
//要新建一个节点放进去 ,new TrieNode() 不然会出现引用
node.put(currentChar, new TrieNode());
}
//沿着链接移动到下一个子层,搜索下个字符
node = node.get(currentChar);
}
//到达最后一个,设置为终点
node.setEnd();
}
public boolean search(String word) {
//获取该前缀树
TrieNode node = searchPrefix(word);
//不为空且为终点,则返回true
return node != null && node.isEnd();
}
//TrieNode是私人的private
private TrieNode searchPrefix(String word) {
//获取根节点
TrieNode node = root;
//下面两行可以改成for(char temp:word.toCharArray()){
for (int i = 0; i < word.length(); i++) {
//获取字符
char curLetter = word.charAt(i);
//存在,取该字符,否则,返回null
if (node.containsKey(curLetter)) {
node = node.get(curLetter);
} else {
//这里是return null 而不是 node=null
return null;
}
}
//返回该前缀数
return node;
}
//查找键前缀,而不是整棵树
public boolean startsWith(String prefix) {
//同查找键,区别在于不判断是否在尾巴
TrieNode node = searchPrefix(prefix);
return node != null;
}
}
插入: 时间O(m) 空间(m)
查找键/键前缀: 时间O(m) 空间O(1)