#include <iostream> #include <unordered_map> using namespace std; struct TrieNode { unordered_map<char, TrieNode*> children; bool isEnd = false; }; class Trie { public: TrieNode* root; Trie() { root = new TrieNode(); } void insert(const string& word) { TrieNode* node = root; for (char c : word) { if (!node->children.count(c)) node->children[c] = new TrieNode(); node = node->children[c]; } node->isEnd = true; } bool startsWith(const string& prefix) { TrieNode* node = root; for (char c : prefix) { if (!node->children.count(c)) return false; node = node->children[c]; } return true; } }; int main() { Trie trie; trie.insert("apple"); trie.insert("app"); cout << (trie.startsWith("app") ? "Yes" : "No") << endl; cout << (trie.startsWith("apl") ? "Yes" : "No") << endl; return 0; }
The prefix "app" exists because both "apple" and "app" start with it, so output is "Yes". The prefix "apl" does not exist in any inserted word, so output is "No".
Trie stores characters in a tree structure allowing prefix search by traversing nodes, without storing all prefixes explicitly. Hash Map requires storing all prefixes as keys, which is less efficient.
#include <iostream> #include <unordered_map> #include <vector> using namespace std; int main() { vector<string> words = {"cat", "car", "cart", "dog"}; unordered_map<string, int> prefixCount; for (const string& word : words) { for (int i = 1; i <= word.size(); ++i) { prefixCount[word.substr(0, i)]++; } } cout << prefixCount["car"] << endl; cout << prefixCount["ca"] << endl; cout << prefixCount["do"] << endl; cout << prefixCount["c"] << endl; return 0; }
"car" is prefix of "car" and "cart" → 2
"ca" is prefix of "cat", "car", "cart" → 3
"do" is prefix of "dog" → 1
"c" is prefix of "cat", "car", "cart" → 3
#include <iostream> #include <unordered_map> using namespace std; struct TrieNode { unordered_map<char, TrieNode*> children; bool isEnd = false; }; class Trie { public: TrieNode* root; Trie() { root = new TrieNode(); } void insert(const string& word) { TrieNode* node = root; for (char c : word) { if (!node->children[c]) node->children[c] = new TrieNode(); node = node->children[c]; } node->isEnd = true; } bool startsWith(const string& prefix) { TrieNode* node = root; for (char c : prefix) { if (node->children.count(c) == 0) return false; node = node->children[c]; } return true; } }; int main() { Trie trie; trie.insert("hello"); cout << (trie.startsWith("hel") ? "Yes" : "No") << endl; return 0; }
Using operator[] on unordered_map with a missing key inserts a new entry with default value (nullptr here), so the check 'node->children[c] == nullptr' is true only after insertion, but operator[] itself modifies the map unexpectedly, which can cause logic errors or unexpected behavior.
Trie stores prefixes in shared nodes, so common prefixes are stored once, saving memory. Hash Map stores each prefix as a separate key, leading to higher memory usage.