目录
一、题目描述
实现一个 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 构成的。
- 保证所有输入均为非空字符串。
二、解题思路
前缀树又叫字典树,是一个多叉树的结构。是由父节点通过指针指向子节点来表示父节点所代表字母的下一个字母是子节点所代表的的字母。按照都是小写字母的要求,任何一个字母的后面可能出现的字母有26个,所以是一个26叉树结构。在这个结构上还需要维护一个bool变量来表示当前字母是否到了单词的结尾,方便查找。
树节点的结构:
//节点的结构
//指针数组形式
class node {
public:
node* trieNode[26] = { nullptr };
bool isEnd;
node() {
isEnd = false;
}
~node() {
for (int i = 0; i < 26; i++) {
if (trieNode[i]) {
delete trieNode[i];
}
}
}
};
前缀树的结构:
class Trie {
public:
/** Initialize your data structure here. */
node* root;
Trie() {
root = new node();
}
~Trie() {
delete root;
}
/** Inserts a word into the trie. */
void insert(string word) {
}
/** Returns if the word is in the trie. */
bool search(string word) {
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
}
};
insert操作:
按照string的字母顺序,一个一个字母的往树里面添加节点,到最后一个字符的时候把isEnd置为true。
void insert(string word) {
int n = word.size();
node * p = root;
for (int i = 0; i < n; i++) {
int c = word[i] - 'a';
if (!p->trieNode[c]) {
p->trieNode[c] = new node();
}
p = p->trieNode[c];
}
p->isEnd = true;
}
search操作:
从字符串开头一个一个往下查找。如果存在串中的某个单词不在树中或者结尾标记不为true,则查找失败,不在要查找的单词。
/** Returns if the word is in the trie. */
bool search(string word) {
int length = word.size();
node* p = root;
for (int i = 0; i < length; i++) {
int c = word[i] - 'a';
if (!p->trieNode[c]) {
return false;
}
p = p->trieNode[c];
}
return p->isEnd;
}
startsWith操作:
与search操作类似,只是不需要判断结尾标记,只要每一个单词都存在,则存在这个字符串前缀。
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
int length = prefix.size();
node* p = root;
for (int i = 0; i < length; i++) {
int c = prefix[i] - 'a';
if (!p->trieNode[c]) {
return false;
}
p = p->trieNode[c];
}
return true;
}
三、代码实现
整体代码如下:
//节点的结构
//指针数组形式
class node {
public:
node* trieNode[26] = { nullptr };
bool isEnd;
node() {
isEnd = false;
}
~node() {
for (int i = 0; i < 26; i++) {
if (trieNode[i]) {
delete trieNode[i];
}
}
}
};
class Trie {
public:
/** Initialize your data structure here. */
node* root;
Trie() {
root = new node();
}
~Trie() {
delete root;
}
/** Inserts a word into the trie. */
void insert(string word) {
int n = word.size();
node * p = root;
for (int i = 0; i < n; i++) {
int c = word[i] - 'a';
if (!p->trieNode[c]) {
p->trieNode[c] = new node();
}
p = p->trieNode[c];
}
p->isEnd = true;
}
/** Returns if the word is in the trie. */
bool search(string word) {
int length = word.size();
node* p = root;
for (int i = 0; i < length; i++) {
int c = word[i] - 'a';
if (!p->trieNode[c]) {
return false;
}
p = p->trieNode[c];
}
return p->isEnd;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
int length = prefix.size();
node* p = root;
for (int i = 0; i < length; i++) {
int c = prefix[i] - 'a';
if (!p->trieNode[c]) {
return false;
}
p = p->trieNode[c];
}
return true;
}
};