
The Trie data structure is used to store a set of keys represented as strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. A Trie node is a basic element used to build a Trie, consisting of:
// Node Structure for Trie
struct Node {
Node* links[26] = {nullptr}; // Array to store links to child nodes, each index represents a letter
bool flag = false; // flag indicating if the node marks the end of word
// Check if the node contains a specific key (letter)
bool containsKey(char ch) {
return links[ch - 'a'] != nullptr;
}
// Insert a new node with a specific key into the Trie
void put(char ch, Node* node) {
links[ch - 'a'] = node;
}
// Get the node with a specific key from the Trie
Node* get(char ch) {
return links[ch - 'a'];
}
// Set the current node as the end of a word
void setEnd() {
flag = true;
}
// Check if the current node marks the end of a word
bool isEnd() {
return flag;
}
};
class Trie {
public:
Node* root;
// Constructor to initialize the Trie with an empty root node
Trie() {
root = new Node();
}
// Inserts a word into the Trie in O(N)
void insert(string word) {
Node* node = root; // start from root node
for (char ch : word) {
if (!node->containsKey(ch)) {
node->put(ch, new Node()); // Create a new node for the letter if not present
}
node = node->get(ch); // Move to the next node
}
node->setEnd(); // Mark the end of the word
}
// Returns true if the word is in the trie
bool search(string word) {
Node* node = root;
for (char ch : word) {
if (!node->containsKey(ch)) {
return false; // letter not found
}
node = node->get(ch);
}
return node->isEnd(); // Check if the last node marks the end of a word
}
// Returns True if there is any word in the trie that starts with the given prefix
bool startsWith(string prefix) {
Node* node = root;
for (char ch : prefix) {
if (!node->containsKey(ch)) {
return false;
}
node = node->get(ch);
}
return true; // Prefix Found
}
};
O(N) for all operations.In Trie , we have to implement the following:-
struct Node {
Node* links[26]; // child links
int cntEndWith = 0; // Counter for no. of words that end at this node
int cntPrefix = 0; // Counter for no. of words that have this node as a prefix
bool containsKey(char ch) {
return links[ch - 'a'] != nullptr;
}
Node* get(char ch) {
return links[ch - 'a'];
}
void put(char ch, Node* node) {
links[ch - 'a'] = node;
}
// Func to increment the count of words that end at this node
void increaseEnd() {
cntEndWith++;
}
// Func to increment the count of words that have this node as a prefix
void increasePrefix() {
cntPrefix++;
}
// Func to decrement the count of words that end at this node
void deleteEnd() {
cntEndWith--;
}
//Func to decrement the count of words that have this node as a prefix
void reducePrefix() {
cntPrefix--;
}
};
class Trie {
public:
Node* root;
Trie() {
root = new Node();
}
void insert(string word) {
Node* node = root;
for (int i = 0; i < word.size(); i++) {
if (!node->containsKey(word[i])) {
node->put(word[i], new Node());
}
node = node->get(word[i]);
// Increment the prefix count for the node
node->increasePrefix();
}
// Increment the end count for the last node of the word
node->increaseEnd();
}
int countWordsEqualTo(string word) {
Node* node = root;
for (int i = 0; i < word.size(); i++) {
if (node->containsKey(word[i])) {
node = node->get(word[i]); // move to the child
} else {
// character is not found
return 0;
}
}
// Return the count of words ending at the node
return node->cntEndWith;
}
int countWordsStartingWith(string word) {
Node* node = root;
for (int i = 0; i < word.size(); i++) {
if (node->containsKey(word[i])) {
node = node->get(word[i]);
} else {
return 0;
}
}
// Return the count of words with the prefix
return node->cntPrefix;
}
void erase(string word) {
Node* node = root;
for (int i = 0; i < word.size(); i++) {
if (node->containsKey(word[i])) {
node = node->get(word[i]);
// Decrement the prefix count for the node
node->reducePrefix();
} else {
return;
}
}
// Decrement the end count for the last node of the word
node->deleteEnd();
}
};
struct Node {
Node* links[26] = {nullptr};
bool flag = false;
bool containsKey(char ch) {
return links[ch - 'a'] != NULL;
}
void put(char ch, Node* node) {
links[ch - 'a'] = node;
}
Node* get(char ch) {
return links[ch - 'a'];
}
void setEnd() {
flag = true;
}
bool isEnd() {
return flag;
}
};
class Trie {
public:
Node* root;
Trie() {
root = new Node();
}
void insert(string word){
Node* node = root;
for (int i = 0; i < word.size(); i++){
if (!node->containsKey(word[i])){
node->put(word[i], new Node());
}
node = node->get(word[i]);
}
node->setEnd();
}
bool foundAllPrefix(string word){
Node* node = root;
for (char ch : word){
if (!node->containsKey(ch)) return false;
node = node->get(ch);
if (!node->isEnd()) return false; // prefix not marked as end
}
return true;
}
};
class Solution {
public:
string longestValidWord(vector<string>& words) {
Trie trie;
for (auto it : words){
trie.insert(it);
}
string ans = "";
for (auto it : words){
if (trie.foundAllPrefix(it)){
if (it.size() > ans.size()) ans = it;
else if (it.size() == ans.size() && it < ans) ans = it;
}
}
return ans;
}
};
struct Node {
Node* links[26] = {nullptr};
bool containsKey(char ch) {
return links[ch - 'a'] != NULL;
}
void put(char ch, Node* node) {
links[ch - 'a'] = node;
}
Node* get(char ch) {
return links[ch - 'a'];
}
};
class Solution {
public:
int countSubs(string& s) {
int n = s.size();
Node* root = new Node();
int count = 0;
for (int i = 0; i < n; i++){
Node* node = root;
for (int j = i; j < n; j++){
if (!node->containsKey(s[j])){
node->put(s[j], new Node());
count++; // Increment the counter since a new substring is found
}
node = node->get(s[j]);
}
}
return count + 1; // +1 for empty substring
}
};
0 ^ 0 = 0 , 1 ^ 1 = 0 , 0 ^ 1 = 1 , 1 ^ 0 = 1A ^ B = C implies A ^ C = B(N >> i) & 1(N >> i) & 1 gives the bit at ith positionN | (1 << i)