Trie 前缀树 prefix tree, 又称字典树。它用一个树状的数据结构储存一个字典中的所有单词。是典型的空间换时间的思想。prefix tree is called prefix becaues it is easy to check the prefix of the word.
网上有很多讲Trie的视频和文章,但看完只会对Trie有个非常模糊的认识。跟着下面的习题做完,才能熟悉Trie,解决Trie。习题选择来自剑指offer第十章 前缀树 以及needcode, blind75
前序
例题
Question 1
208. Implement Trie (Prefix Tree) Blind 75
题解来自neetcode c++ 中国区力扣解释微难理解一些。neetcode更好懂
class TrieNode{
public:
TrieNode* children[26];
bool isWord;
TrieNode(){
for(int i = 0; i < 26; i++){
children[i] = nullptr;
}
isWord = false;
}
};
class Trie {
private:
TrieNode* root;
public:
Trie() {
root = new TrieNode();
}
void insert(string word) {
//1. 子节点存在,沿着指针移动到子节点,继续处理下一个字符
// 2.子节点不存在,创建一个新的子节点,记录在children数组的对应位置上,
// 沿着指针移动到子节点,继续搜索下一个字符
// 3.重复以上步骤,直到处理字符串的最后一个字符,将最后一个字符的节点标记为字符串的结尾
TrieNode* node = root;
int curr = 0;
for(int i = 0; i < word.size(); i++){
curr = word[i] - 'a';
if(node->children[curr] == nullptr){
node->children[curr] = new TrieNode();
}
node = node->children[curr];
}
node->isWord = true; //last node mark as true
//can have as many isWord true as possible in one line since prefixes can have same prefixes.
}
bool search(string word) {
/* 子节点存在,沿着指针移动到子节点,继续搜索下一个字符
子节点不存在,说明字典树不包含该前缀,返回false
重复以上步骤,如果搜索完word的最后一个字符且最后节点的isEnd为真,字典树确实存在该字符串
*/
TrieNode* node = root;
int curr = 0;
for(int i = 0; i < word.size(); i++){
curr = word[i] - 'a';
if(node->children[curr] == nullptr){
return false;
}
node = node->children[curr];
}
return node->isWord; //make sure the end of the node should be the end.
}
bool startsWith(string prefix) {
TrieNode* node = root;
int curr = 0;
for(int i = 0; i < prefix.size(); i++){
curr = prefix[i] - 'a';
if(node->children[curr] == nullptr){
return false;
}
node = node->children[curr];
}
return true;
}
};
同时,这里因为leetcode自身设计,不用回收废弃指针,但在现实oop中,对于c++一定要注意指针的回收.比如linkedList 等都是一样
有些题解,不是用的TreeNode* children[26]来作为底的Trie class。而是使用
struct Trie {
unordered_map<char, Trie *> children;
};
他标记最后字母节点的方式是:
cur->children['#'] = new Trie();
比如中区648. 单词替换 题解二。很有意思,推荐阅读。
其他问题
648. Replace Words 看完第一题(LC208)细心做就能得出正确答案。- 来自NYU Tandon LeetCode Bootcamp
class Solution {
public:
class TrieNode{
public:
TrieNode* children[26];
bool isWord;
TrieNode(){
for(int i = 0; i < 26; i++){
children[i] = nullptr;
}
isWord = false;
}
};
class Trie{
public:
TrieNode* root;
Trie(){
root = new TrieNode();
}
void insert(string word){
TrieNode* node = root;
for(char c: word){
int curr = c - 'a';
if(node->children[curr] == nullptr)
node->children[curr] = new TrieNode();
node = node->children[curr];
}
node->isWord = true;
}
string search(string word){
string path;
TrieNode* node = root;
for(char c: word){
int curr = c - 'a';
if(node->children[curr] == nullptr || node->isWord) break;
path += c;
node = node->children[curr];
}
return node->isWord == true? path:word;
}
};
string replaceWords(vector<string>& dictionary, string sentence) {
if(dictionary.size() == 0) return sentence;
if(sentence.size() == 0) return "";
Trie dic;
for(string str: dictionary){
dic.insert(str);
}
//separate the sentence into the words vector
vector<string> separated;
int i = 0;
string curr = "";
while(i < sentence.size()){
if(sentence[i] == ' '){
separated.push_back(curr);
curr = "";
} else{
curr += sentence[i];
}
i++;
}
separated.push_back(curr);
string ans = "";
for(string str: separated){
ans = ans + dic.search(str) + " ";
}
ans.pop_back();
return ans;
}
};
211. Design Add and Search Words Data Structure Blind 75 208变种题 dfs related. 题解看neetcode. 真是贼有意思的题。和dfs结合考,哪个不会都做不出来。# 79. 单词搜索 也是和dfs结合考。也没第一遍做出来。dfs真的需要重新学习一下了。tree常考dfs
class TrieNode{
public:
TrieNode* children[26];
bool isWord;
TrieNode(){
for(int i = 0; i < 26; i++){
children[i] = nullptr;
}
isWord = false;
}
};
class WordDictionary {
private:
TrieNode* root;
public:
WordDictionary() {
root = new TrieNode();
}
void addWord(string word) {
//add word is normal as TrieNode add.
TrieNode* node = root;
int curr = 0;
for(int i = 0; i < word.size(); i++){
curr = word[i] - 'a';
if(node->children[curr] == nullptr){
node->children[curr] = new TrieNode();
}
node = node->children[curr];
}
node->isWord = true;
}
bool search(string word) {
//there exists '.'. dots can be matched with any letter.
TrieNode* node = root;
return searchInNode(word, 0, node);
}
private:
bool searchInNode(string& word, int i, TrieNode* node){
if(node == nullptr) return false;
if(i == word.size()) return node->isWord;
if(word[i] != '.') return searchInNode(word, i+1, node->children[word[i]-'a']);
for(int j = 0; j < 26; j++){
if(searchInNode(word, i+1, node->children[j])){
return true;
}
}
return false;
}
};
复习这道题的时候在反应dfs,dfs就是recursive function. 就像树一样。
139. Word Break Blind75 1-dynamic中的题 用trie解会节约时间。
212. Word Search II extra: 回溯经典题 79. Word Search Blind 75
Leetcode 720 Leetcode 692
Extra materials
Recommended by NYU Leetcode Bootcamp recommended by instructor Spriha Jha