2024 6/28 马上就到七月了,今天下午有个考试加上明天下午有个汇报那期末就基本结束了。做一题先
1、题目描述
2、算法分析
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前缀树图解。
3、代码呈现
// 定义一个数组用于存储当前节点的子节点,数组长度为26,对应26个小写英文字母
private Trie[] children;
// 标记当前节点是否为一个单词的结尾
private boolean isEnd;
// 构造函数,初始化一个Trie节点
public Trie() {
// 初始化子节点数组,长度为26,所有元素初始化为null
children = new Trie[26];
// 标记当前节点不是单词的结尾
isEnd = false;
}
// 向字典树中插入一个单词
public void insert(String word) {
// 从根节点开始遍历
Trie node = this;
for(int i = 0; i < word.length(); i++){
// 获取当前字符
char ch = word.charAt(i);
// 计算当前字符在children数组中的索引位置('a' - 'a' = 0, 'b' - 'a' = 1, ...)
int index = ch - 'a';
// 如果当前索引位置的子节点为空,则创建一个新的Trie节点
if(node.children[index] == null){
node.children[index] = new Trie();
}
// 移动到下一个节点
node = node.children[index];
}
// 标记最后一个节点为单词的结尾
node.isEnd = true;
}
// 搜索一个单词是否在字典树中
public boolean search(String word) {
// 搜索单词的前缀,并返回最后一个节点
Trie node = searchPrefix(word);
// 如果节点不为空且该节点是单词的结尾,则返回true,否则返回false
return node != null && node.isEnd;
}
// 判断一个前缀是否在字典树中存在
public boolean startsWith(String prefix) {
// 搜索前缀,如果返回不为空,则表示前缀存在
return searchPrefix(prefix) != null;
}
// 私有方法,用于搜索一个前缀并返回最后一个节点
private Trie searchPrefix(String prefix){
// 从根节点开始遍历
Trie node = this;
for(int i = 0; i < prefix.length(); i++){
// 获取当前字符
char ch = prefix.charAt(i);
int index = ch - 'a';
// 如果当前索引位置的子节点为空,则表示前缀不存在,返回null
if(node.children[index] == null){
return null;
}
// 移动到下一个节点
node = node.children[index];
}
// 返回最后一个节点
return node;
}
4、复杂度分析
- 时间复杂度:初始化为
O(1)
,其余操作为O(∣S∣)
,其中∣S∣
是每次插入或查询的字符串的长度。 - 空间复杂度:
O(∣T∣⋅Σ)
,其中∣T∣
为所有插入字符串的长度之和,Σ
为字符集的大小,本题Σ=26
。
ok,再见