携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情
一、前言
Trie
树(又称字典树、前缀树) ,一棵从二叉树衍生出来的多叉树。
- 核心思想是空间换时间: 利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
前缀树的3个基本性质:
- 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
- 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
- 每个节点的所有子节点包含的字符都不相同。
前缀树模板,可看下面题目1:实现前缀树。
二、题目
(1)实现前缀树Trie
(中)
题干分析
这个题目说的是,你要实现一棵前缀树(Trie
),其中包含 insert
, search
和 startsWith
三个方法。
insert
: 用于插入一个单词search
: 用于搜索一个单词是否存在于前缀树中startsWith
:用于判断前缀树中是否存在一个包含给定前缀的单词。
注意:所有的输入都是非空字符串,并且只包含小写字母。
# 举个栗子:
# 前缀树中有 bbc
\
b
\
b
\
c
# Search 搜索
bbc 能搜索到
bb 搜索不到
# startWith
bb 能查询到
思路解法
首先,定义前缀树的节点 Node
: 一棵 26叉树。
private class TrieNode {
boolean endOfWord; // 是否是一个单词结尾
TrieNode [] children; // 指向 26个 子节点
TrieNode() {
this.endOfWord = false;
this.children = new TrieNode[26];
}
}
举个栗子: 字符串 bbc
- 新增操作
-
搜索单词: 根据树一个节点一个节点搜索
最后,单词的最后一个字母对应的节点的
endOfWord
需要为true
。 -
搜索前缀: 根据树一个节点一个节点搜索
不需要看节点的
endOfWord
是否为true
。
完整代码如下:
// Faster: 87.89%
class Trie {
private class TrieNode {
boolean endOfWord; // 是否是一个单词结尾
TrieNode [] children; // 指向 26个 子节点
TrieNode() {
this.endOfWord = false;
this.children = new TrieNode[26];
}
}
private TrieNode root;
public Trie() {
this.root = new TrieNode();
}
// 新增
public void insert(String word) {
TrieNode cur = root;
for (int i = 0; i < word.length(); ++i) {
int idx = word.charAt(i) - 'a';
if (cur.children[idx] == null) cur.children[idx] = new TrieNode();
cur = cur.children[idx];
}
cur.endOfWord = true;
}
// 搜索
public boolean search(String word) {
TrieNode node = searchEndNode(word);
return node != null && node.endOfWord;
}
// 搜索节点
private TrieNode searchEndNode(String str) {
TrieNode cur = root;
for (int i = 0; i < str.length() && cur != null; ++i) {
int idx = str.charAt(i) - 'a';
cur = cur.children[idx];
}
return cur;
}
// 搜索前缀
public boolean startsWith(String prefix) {
TrieNode node = searchEndNode(prefix);
return node != null;
}
}