Trie
2015-09-03 18:20
633 查看
只要把数据结构想清楚了,其实 Trie 树很简单的。
摘自百度百科
字典树,又称单词查找树。利用字符串的公共前缀来减少查询时间。
典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。
它有3个基本性质:
根节点不包含字符,除根节点外每一个节点都只包含一个字符;
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
每个节点的所有子节点包含的字符都不相同。
Implement a trie with insert, search, and startsWith methods.
Note: You may assume that all inputs are consist of lowercase letters a-z.
TrieNode 包含三个变量,当前结点所对应的字符,当前结点是否为单词(本题中,由于可以用位置代表当前字符,所以,该变量不是必须的,下面的实现中其实也没有用到),当前结点的孩子结点(用指针数组来表示,大小已定)。还可以考虑删除操作,以及重复插入的情况。
next 有不同的实现方式。
Trie 记录树根,提供相关服务。search 和 startsWith 的大部分内容是一样的,故提取出 find 函数。
Design a data structure that supports the following two operations:
search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter.
Given a 2D board and a list of words from the dictionary, find all words in the board.
摘自百度百科
字典树,又称单词查找树。利用字符串的公共前缀来减少查询时间。
典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。
它有3个基本性质:
根节点不包含字符,除根节点外每一个节点都只包含一个字符;
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
每个节点的所有子节点包含的字符都不相同。
Implement Trie (Prefix Tree)
https://leetcode.com/problems/implement-trie-prefix-tree/Implement a trie with insert, search, and startsWith methods.
Note: You may assume that all inputs are consist of lowercase letters a-z.
TrieNode 包含三个变量,当前结点所对应的字符,当前结点是否为单词(本题中,由于可以用位置代表当前字符,所以,该变量不是必须的,下面的实现中其实也没有用到),当前结点的孩子结点(用指针数组来表示,大小已定)。还可以考虑删除操作,以及重复插入的情况。
next 有不同的实现方式。
TrieNode* next[26]; // fast, Runtime: 56 ms memset(next, 0, sizeof(TrieNode*)* 26); // initialize vector<TrieNode*> children; // middle, Runtime: 108 ms children(vector<TrieNode*>(26, nullptr)) // initialize unordered_map<char, TrieNode*> next; // slow, Runtime: 188 ms without deconstruct, 228 ms with deconstruct
Trie 记录树根,提供相关服务。search 和 startsWith 的大部分内容是一样的,故提取出 find 函数。
#include <string> using std::string; // Runtime: 64 ms with destructor // Runtime: 56 ms without destructor // https://leetcode.com/discuss/34832/two-c-o-n-solutions-array-or-hashtable class TrieNode { public: // Initialize your data structure here. TrieNode() : c(0), isWord(false) { memset(next, 0, sizeof(TrieNode*)* 26); } TrieNode(char _c) : c(_c), isWord(false) { memset(next, 0, sizeof(TrieNode*)* 26); } ~TrieNode() { delete []next; } TrieNode* next[26]; char c; bool isWord; }; class Trie { public: Trie() { root = new TrieNode(); } ~Trie() { destroy(root); } void destroy(TrieNode* node) { for (int i = 0; i < 26; i++) { if (node->next[i]) { destroy(node->next[i]); } } delete node; } // Inserts a word into the trie. void insert(string word) { TrieNode* p = root; for (auto ch : word) { int index = ch - 'a'; if (!p->next[index]) { p->next[index] = new TrieNode(ch); } p = p->next[index]; } p->isWord = true; } // Returns if the word is in the trie. bool search(string word) { TrieNode* p = find(word); return p && p->isWord; } // Returns if there is any word in the trie // that starts with the given prefix. bool startsWith(string prefix) { return find(prefix) != nullptr; } private: TrieNode* find(string key) { TrieNode* p = root; for (auto ch : key) { p = p->next[ch - 'a']; if (!p) { break; } } return p; } TrieNode* root; }; // Your Trie object will be instantiated and called as such: // Trie trie; // trie.insert("somestring"); // trie.search("key");
Add and Search Word - Data structure design
https://leetcode.com/problems/add-and-search-word-data-structure-design/Design a data structure that supports the following two operations:
void addWord(word) bool search(word)
search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter.
#include <string> using std::string; // Runtime: 76 ms // we doesn't need a character c. class TrieNode{ public: // Initialize your data structure here. TrieNode() : isWord(false) { memset(next, 0, sizeof(TrieNode*)* 26); } TrieNode(char _c) : c(_c), isWord(false) { memset(next, 0, sizeof(TrieNode*)* 26); } ~TrieNode() { delete []next; } TrieNode* next[26]; char c; bool isWord; }; class WordDictionary { public: WordDictionary() { root = new TrieNode(); } // Adds a word into the data structure. void addWord(string word) { TrieNode* p = root; for (auto ch : word) { int index = ch - 'a'; if (!p->next[index]) { //if (p->next[index] == nullptr) { p->next[index] = new TrieNode(ch); } p = p->next[index]; } p->isWord = true; } // Returns if the word is in the data structure. A word could // contain the dot character '.' to represent any one letter. bool search(string word) { return searchHelper(word.c_str(), root); } private: //bool searchHelper(const char* word, TrieNode* node) { // for (int i = 0; word[i]; i++) { // if (node && word[i] != '.') { // node = node->next[word[i] - 'a']; // } // else if (node && word[i] == '.') { // for (int j = 0; j < 26; j++) { // if (searchHelper(word + i + 1, node->next[j])) { // return true; // } // } // // 'a', search(".a") or search("a.") // return false; // } // else { // break; // } // } // return node && node->isWord; //} bool searchHelper(const char* word, TrieNode* node) { // Runtime: 80 ms if (!node) { return false; } if (*word == '\0') { return node->isWord; } else if (*word == '.') { for (int j = 0; j < 26; j++) { if (searchHelper(word + 1, node->next[j])) { return true; } } return false; } else { return searchHelper(word + 1, node->next[*word - 'a']); } } TrieNode* root; }; // Your WordDictionary object will be instantiated and called as such: // WordDictionary wordDictionary; // wordDictionary.addWord("word"); // wordDictionary.search("pattern");
Word Search II
https://leetcode.com/problems/word-search-ii/Given a 2D board and a list of words from the dictionary, find all words in the board.
#include <string> #include <vector> #include <set> #include <unordered_map> using std::string; using std::vector; using std::set; using std::unordered_map; // Runtime: 52 ms void insert(string word, int i) // Best: 48 ms void insert(vector<string>& words, int i) class TrieNode { public: TrieNode() : isWord(false), isUsed(false), index(-1) { memset(next, 0, sizeof(TrieNode*)* 26); } TrieNode* next[26]; bool isWord; bool isUsed; int index; }; class Trie { public: Trie() { root = new TrieNode(); } void insert(string word, int i) { TrieNode* p = root; for (auto ch : word) { if (!p->next[ch - 'a']) { p->next[ch - 'a'] = new TrieNode(); } p = p->next[ch - 'a']; } p->isWord = true; p->isUsed = false; p->index = i; } void insert(vector<string>& words, int i) { TrieNode* p = root; for (auto ch : words[i]) { if (!p->next[ch - 'a']) { p->next[ch - 'a'] = new TrieNode(); } p = p->next[ch - 'a']; } p->isWord = true; p->isUsed = false; p->index = i; } void insert(vector<string>& words) { for (int i = 0; i < words.size(); i++) { // insert(words[i], i); insert(words, i); } } vector<string> findWords(vector<vector<char>>& board, vector<string>& words) { vector<string> ret; const int ROW = board.size(); const int COL = board[0].size(); for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { findWords(ret, words, root, board, i, j, ROW, COL); } } return ret; } void findWords(vector<string>& ret, vector<string>& words, TrieNode* node, vector<vector<char>>&board, int i, int j, const int Row, const int Col) { // doesn't need count, because node->next[index] will be nullptr. // 60 ms if (board[i][j] == '.') { return; } int index = board[i][j] - 'a'; TrieNode* next = node->next[index]; if (next) { char tmp = board[i][j]; if (next->isWord && !next->isUsed) { ret.push_back(words[next->index]); next->isUsed = true; } board[i][j] = '.'; if (i > 0) { findWords(ret, words, next, board, i - 1, j, Row, Col); } if (i + 1 < Row) { findWords(ret, words, next, board, i + 1, j, Row, Col); } if (j > 0) { findWords(ret, words, next, board, i, j - 1, Row, Col); } if (j + 1 < Col) { findWords(ret, words, next, board, i, j + 1, Row, Col); } board[i][j] = tmp; } } private: TrieNode* root; }; class Solution { public: vector<string> findWords(vector<vector<char>>& board, vector<string>& words) { vector<string> ret; if (board.empty() || board[0].empty()) { return ret; } Trie trie; trie.insert(words); return trie.findWords(board, words); } };
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- C++ Custom Control控件向父窗体发送对应的消息
- C++中拷贝构造函数的应用详解