前缀树
在计算机科学中,trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。
- 根据前缀信息选择树上的分支,可以节省大量时间。但比较浪费空间。
| |
| void Trie(); |
| |
| void insert(string word); |
| |
| int search(string word); |
| |
| int prefixNumber(string prefix); |
| |
| void remove(string word); |
动态结构实现
| #include <vector> |
| #include <cstdlib> |
| #include <ctime> |
| #include <string> |
| #include <unordered_map> |
| |
| using namespace std; |
| |
| class TrieNode { |
| public: |
| int pass; |
| int end; |
| |
| vector<TrieNode *> nexts; |
| |
| TrieNode() { |
| pass = 0; |
| end = 0; |
| nexts.resize(26); |
| } |
| }; |
| |
| class Trie { |
| private: |
| TrieNode *root; |
| public: |
| Trie() { |
| root = new TrieNode; |
| } |
| |
| |
| void insert(string word) { |
| TrieNode *cur = root; |
| cur->pass++; |
| for (int i = 0, path; i < word.length(); ++i) { |
| path = word[i] - 'a'; |
| if (cur->nexts[path] == nullptr) cur->nexts[path] = new TrieNode(); |
| cur = cur->nexts[path]; |
| cur->pass++; |
| } |
| cur->end++; |
| } |
| |
| |
| int search(string word) { |
| TrieNode *cur = root; |
| for (int i = 0, path; i < word.length(); ++i) { |
| path = word[i] - 'a'; |
| if (cur->nexts[path] == nullptr) return 0; |
| cur = cur->nexts[path]; |
| } |
| return cur->end; |
| } |
| |
| |
| int prefixNumber(string prefix) { |
| TrieNode *cur = root; |
| for (int i = 0, path; i < prefix.length(); ++i) { |
| path = prefix[i] - 'a'; |
| if (cur->nexts[path] == nullptr) return 0; |
| cur = cur->nexts[path]; |
| } |
| return cur->pass; |
| } |
| |
| |
| void remove(string word) { |
| if (search(word) <= 0) return; |
| TrieNode *cur = root; |
| cur->pass--; |
| for (int i = 0, path; i < word.length(); ++i) { |
| path = word[i] - 'a'; |
| cur->nexts[path]--; |
| if (cur->nexts[path]->pass == 0) { |
| |
| cur->nexts[path] = nullptr; |
| return; |
| } |
| cur = cur->nexts[path]; |
| } |
| cur->end--; |
| } |
| }; |
静态结构实现
| #include <vector> |
| #include <string> |
| #include <iostream> |
| |
| using namespace std; |
| |
| class Trie { |
| public: |
| vector<vector<int>> tree; |
| vector<int> pass; |
| vector<int> end; |
| int cnt; |
| const int maxN = 150001; |
| |
| void build() { |
| cnt = 1; |
| tree.resize(maxN, vector<int>(26)); |
| pass.resize(maxN, 0); |
| end.resize(maxN, 0); |
| } |
| |
| void insert(string word) { |
| int cur = 1; |
| pass[cur]++; |
| for (int i = 0, path; i < word.length(); ++i) { |
| path = word[i] - 'a'; |
| if (tree[cur][path] == 0) |
| tree[cur][path] = ++cnt; |
| cur = tree[cur][path]; |
| pass[cur]++; |
| } |
| end[cur]++; |
| } |
| |
| int search(string word) { |
| int cur = 1; |
| for (int i = 0, path; i < word.length(); ++i) { |
| path = word[i] - 'a'; |
| if (tree[cur][path] == 0) return 0; |
| cur = tree[cur][path]; |
| } |
| return end[cur]; |
| } |
| |
| int prefixNumber(string word) { |
| int cur = 1; |
| for (int i = 0, path; i < word.length(); ++i) { |
| path = word[i] - 'a'; |
| if (tree[cur][path] == 0) return 0; |
| cur = tree[cur][path]; |
| } |
| return pass[cur]; |
| } |
| |
| void remove(string word) { |
| if (search(word) <= 0) return; |
| int cur = 1; |
| for (int i = 0, path; i < word.length(); ++i) { |
| path = word[i] - 'a'; |
| if (--pass[tree[cur][path]] == 0) { |
| tree[cur][path] = 0; |
| return; |
| } |
| cur = tree[cur][path]; |
| } |
| end[cur]--; |
| } |
| }; |
| |
| int main() { |
| int m; |
| cin >> m; |
| |
| Trie trie; |
| trie.build(); |
| |
| for (int i = 0; i < m; ++i) { |
| int opt; |
| string word; |
| cin >> opt >> word; |
| switch (opt) { |
| case 1: |
| trie.insert(word); |
| break; |
| case 2: |
| trie.remove(word); |
| break; |
| case 3: |
| cout << (trie.search(word) > 0 ? "YES" : "NO") << endl; |
| break; |
| case 4: |
| cout << trie.prefixNumber(word) << endl; |
| break; |
| } |
| } |
| } |
| #include <vector> |
| #include <string> |
| #include <iostream> |
| |
| using namespace std; |
| |
| class Trie { |
| public: |
| vector<vector<int>> tree; |
| vector<int> pass; |
| vector<int> end; |
| int cnt; |
| const int maxN = 2000001; |
| |
| void build() { |
| cnt = 1; |
| tree.resize(maxN, vector<int>(12)); |
| pass.resize(maxN, 0); |
| end.resize(maxN, 0); |
| } |
| |
| |
| |
| |
| int getPath(char ch) { |
| if (ch == '#') { |
| return 10; |
| } else if (ch == '-') { |
| return 11; |
| } else { |
| return ch - '0'; |
| } |
| } |
| |
| void insert(string word) { |
| int cur = 1; |
| pass[cur]++; |
| for (int i = 0, path; i < word.length(); ++i) { |
| path = getPath(word[i]); |
| if (tree[cur][path] == 0) |
| tree[cur][path] = ++cnt; |
| cur = tree[cur][path]; |
| pass[cur]++; |
| } |
| end[cur]++; |
| } |
| |
| int prefixNumber(string word) { |
| int cur = 1; |
| for (int i = 0, path; i < word.length(); ++i) { |
| path = getPath(word[i]); |
| if (tree[cur][path] == 0) return 0; |
| cur = tree[cur][path]; |
| } |
| return pass[cur]; |
| } |
| }; |
| |
| class Solution { |
| public: |
| vector<int> countConsistentKeys(vector<vector<int>> &b, vector<vector<int>> &a) { |
| Trie trie; |
| trie.build(); |
| |
| |
| for (const auto &item: a) { |
| string str = ""; |
| |
| for (int i = 1; i < item.size(); ++i) |
| str.append(to_string(item[i] - item[i - 1]) + "#"); |
| trie.insert(str); |
| } |
| |
| vector<int> res; |
| for (const auto &item: b) { |
| string str = ""; |
| for (int i = 1; i < item.size(); ++i) |
| str.append(to_string(item[i] - item[i - 1]) + "#"); |
| res.emplace_back(trie.prefixNumber(str)); |
| } |
| return res; |
| } |
| }; |
| #include <vector> |
| #include <string> |
| #include <iostream> |
| |
| using namespace std; |
| |
| vector<vector<int>> tree; |
| int cnt; |
| |
| int high; |
| |
| |
| int countLeadingZeros(int i) { |
| if (i <= 0) return i == 0 ? 32 : 0; |
| |
| int n = 31; |
| |
| if (i >= 1 << 16) { |
| |
| |
| n -= 16; |
| |
| i = (unsigned) i >> 16; |
| } |
| if (i >= 1 << 8) { |
| n -= 8; |
| i = (unsigned) i >> 8; |
| } |
| if (i >= 1 << 4) { |
| n -= 4; |
| i = (unsigned) i >> 4; |
| } |
| if (i >= 1 << 2) { |
| n -= 2; |
| i = (unsigned) i >> 2; |
| } |
| return n - ((unsigned) i >> 1); |
| } |
| |
| class Solution { |
| public: |
| void insert(int num) { |
| int cur = 1; |
| |
| for (int i = high, state; i >= 0; i--) { |
| |
| state = (num >> i) & 1; |
| if (tree[cur][state] == 0) |
| tree[cur][state] = ++cnt; |
| cur = tree[cur][state]; |
| } |
| } |
| |
| void build(vector<int> &nums) { |
| tree.resize(3000001, vector<int>(2, 0)); |
| cnt = 1; |
| int m = INT_MIN; |
| for (int num: nums) |
| m = max(num, m); |
| high = 31 - countLeadingZeros(m); |
| |
| for (int num: nums) |
| insert(num); |
| } |
| |
| int maxXor(int num) { |
| int res = 0; |
| int cur = 1; |
| for (int i = high, state, want; i >= 0; i--) { |
| state = (num >> i) & 1; |
| |
| want = state ^ 1; |
| if (tree[cur][want] == 0) { |
| |
| want ^= 1; |
| } |
| |
| res |= (state ^ want) << i; |
| cur = tree[cur][want]; |
| } |
| return res; |
| } |
| |
| void clear() { |
| for (int i = 1; i <= cnt; i++) |
| tree[i][0] = tree[i][1] = 0; |
| } |
| |
| int findMaximumXOR(vector<int> &nums) { |
| build(nums); |
| int res = 0; |
| for (int num: nums) |
| res = max(res, maxXor(num)); |
| clear(); |
| return res; |
| } |
| }; |
| #include <vector> |
| #include <string> |
| #include <iostream> |
| #include <unordered_set> |
| #include <algorithm> |
| |
| using namespace std; |
| |
| |
| int countLeadingZeros(int i) { |
| if (i <= 0) return i == 0 ? 32 : 0; |
| |
| int n = 31; |
| |
| if (i >= 1 << 16) { |
| |
| |
| n -= 16; |
| |
| i = (unsigned) i >> 16; |
| } |
| if (i >= 1 << 8) { |
| n -= 8; |
| i = (unsigned) i >> 8; |
| } |
| if (i >= 1 << 4) { |
| n -= 4; |
| i = (unsigned) i >> 4; |
| } |
| if (i >= 1 << 2) { |
| n -= 2; |
| i = (unsigned) i >> 2; |
| } |
| return n - ((unsigned) i >> 1); |
| } |
| |
| |
| class Solution { |
| public: |
| int findMaximumXOR(vector<int> &nums) { |
| int m = INT_MIN; |
| for (int num: nums) m = max(num, m); |
| int res = 0; |
| unordered_set<int> set; |
| for (int i = 31 - countLeadingZeros(m); i >= 0; i--) { |
| |
| int better = res | (1 << i); |
| set.clear(); |
| for (int num: nums) { |
| |
| num = (num >> i) << i; |
| set.emplace(num); |
| |
| if (set.find(better ^ num) != set.end()) { |
| res = better; |
| break; |
| } |
| } |
| } |
| return res; |
| } |
| }; |
| #include <vector> |
| #include <string> |
| #include <unordered_set> |
| #include <cstring> |
| |
| using namespace std; |
| |
| class Solution { |
| public: |
| |
| static vector<string> findWords(vector<vector<char>> &board, vector<string> &words) { |
| build(words); |
| vector<string> ans; |
| for (int i = 0; i < board.size(); i++) { |
| for (int j = 0; j < board[0].size(); j++) { |
| dfs(board, i, j, 1, ans); |
| } |
| } |
| clear(); |
| return ans; |
| } |
| |
| private: |
| static const int MAXN = 10001; |
| static int tree[MAXN][26]; |
| static int pass[MAXN]; |
| static string end[MAXN]; |
| static int cnt; |
| |
| static void build(vector<string> &words) { |
| cnt = 1; |
| for (const string &word: words) { |
| int cur = 1; |
| pass[cur]++; |
| for (char c: word) { |
| int path = c - 'a'; |
| if (tree[cur][path] == 0) { |
| tree[cur][path] = ++cnt; |
| } |
| cur = tree[cur][path]; |
| pass[cur]++; |
| } |
| end[cur] = word; |
| } |
| } |
| |
| static void clear() { |
| for (int i = 1; i <= cnt; i++) { |
| memset(tree[i], 0, sizeof(tree[i])); |
| pass[i] = 0; |
| end[i].clear(); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| static int dfs(vector<vector<char>> &board, int i, int j, int t, vector<string> &ans) { |
| if (i < 0 || i == board.size() || j < 0 || j == board[0].size() || board[i][j] == 0) { |
| return 0; |
| } |
| |
| |
| char tmp = board[i][j]; |
| |
| |
| |
| |
| |
| int road = tmp - 'a'; |
| t = tree[t][road]; |
| if (pass[t] == 0) { |
| return 0; |
| } |
| |
| |
| int fix = 0; |
| if (!end[t].empty()) { |
| fix++; |
| ans.push_back(end[t]); |
| end[t].clear(); |
| } |
| |
| board[i][j] = 0; |
| fix += dfs(board, i - 1, j, t, ans); |
| fix += dfs(board, i + 1, j, t, ans); |
| fix += dfs(board, i, j - 1, t, ans); |
| fix += dfs(board, i, j + 1, t, ans); |
| pass[t] -= fix; |
| board[i][j] = tmp; |
| return fix; |
| } |
| }; |
| |
| int Solution::tree[MAXN][26]; |
| int Solution::pass[MAXN]; |
| string Solution::end[MAXN]; |
| int Solution::cnt; |
本文作者:n1ce2cv
本文链接:https://www.cnblogs.com/sprinining/p/18434526
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步