Given a Trie containing lowercase English words and a string key, delete the given key from the Trie. If the key is not present, the Trie should remain unchanged.
Examples:
Input: word[] = ["apple", "app", "apply", "bat"], key = "app"
Output: ["apple", "apply", "bat"]
Explanation: The word "app" is deleted from the Trie. The words "apple", "apply", and "bat" remain unchanged.Input: word[] = ["cat", "car", "dog"], key = "dog"
Output: ["cat", "car"]
Explanation: The word "dog" is deleted from the Trie, while "cat" and "car" remain in the Trie.Input: word[] = ["cat", "car"], key = "can"
Output: ["cat", "car"]
Explanation: The word "can" is not present in the Trie, so the Trie remains unchanged.
The key is deleted from the Trie using recursion in a bottom-up manner.
- First, traverse the Trie to reach the last character of the key.
- Set the isEndOfWord flag of the last node to false.
- While returning from recursion, delete a node if it is not the end of another word and has no children.
- Never delete the root node.
Consider a Trie containing ["car", "card", "care", "dog"].

The following cases explain the deletion process.
Case 1: Key is not present in the Trie
Suppose the key to delete is "can".
- Traverse the Trie through c and a.
- Since the node for n does not exist, the key is not present.
- Return without modifying the Trie.
Thus, all words remain unchanged: ["car", "card", "care", "dog"].
Case 2: The key is a prefix of another word
Suppose the key to delete is "car".
- Traverse the Trie to reach the last character r.
- Set the isEndOfWord flag of node r to false.
- Do not delete node r because it has children d and e, which are needed to form "card" and "care".

Thus, the remaining words are ["card", "care", "dog"].
Case 3: Key shares a prefix with other words
Suppose the key to delete is "card".
- Traverse the Trie to reach the last character d.
- Set the isEndOfWord flag of node d to false.
- Delete node d because it has no children and is not the end of another word.
- Move backwards to node r. Retain it because it is needed by "car" and "care".

Thus, the remaining words are ["car", "care", "dog"].
Case 4: The key does not share its path with any other word
Suppose the key to delete is "dog".
- Traverse the Trie to reach the last character g.
- Set the isEndOfWord flag of node g to false.
- Delete node g because it has no children.
- Move backwards and delete nodes o and d because they are not needed by any other word.
- Stop at the root, which is never deleted.

Thus, the remaining words are ["car", "card", "care"].
#include <bits/stdc++.h>
using namespace std;
class TrieNode {
public:
TrieNode* children[26];
bool isEndOfWord;
TrieNode() {
for (int i = 0; i < 26; i++) {
children[i] = nullptr;
}
isEndOfWord = false;
}
};
// Check whether a node has any children
bool isItFreeNode(TrieNode* node) {
for (int i = 0; i < 26; i++) {
if (node->children[i] != nullptr) {
return false;
}
}
return true;
}
// Recursively delete a key from the Trie
TrieNode* deleteHelper(TrieNode* node, string& key, int depth) {
if (node == nullptr) {
return nullptr;
}
// If we have reached the end of the key
if (depth == (int)key.size()) {
// Key is not present
if (!node->isEndOfWord) {
return node;
}
// Remove the end-of-word mark
node->isEndOfWord = false;
// Delete this node if it has no children
if (depth != 0 && isItFreeNode(node)) {
delete node;
return nullptr;
}
return node;
}
int index = key[depth] - 'a';
// Recursively delete the remaining characters
node->children[index] = deleteHelper(
node->children[index], key, depth + 1
);
// Delete the current node if it is no longer needed
if (depth != 0 && !node->isEndOfWord && isItFreeNode(node)) {
delete node;
return nullptr;
}
return node;
}
void deleteKey(TrieNode* root, string key) {
if (root == nullptr || key.empty()) {
return;
}
deleteHelper(root, key, 0);
}
// Insert a key into the Trie
void insert(TrieNode* root, string key) {
TrieNode* curr = root;
for (char ch : key) {
int index = ch - 'a';
if (curr->children[index] == nullptr) {
curr->children[index] = new TrieNode();
}
curr = curr->children[index];
}
curr->isEndOfWord = true;
}
// Search for a key in the Trie
bool search(TrieNode* root, string key) {
TrieNode* curr = root;
for (char ch : key) {
int index = ch - 'a';
if (curr->children[index] == nullptr) {
return false;
}
curr = curr->children[index];
}
return curr->isEndOfWord;
}
int main() {
// Create a Trie
TrieNode* root = new TrieNode();
// Insert keys into the Trie
vector<string> words = {"car", "card", "care", "dog"};
for (string word : words) {
insert(root, word);
}
// Key to delete
string key = "card";
// Delete the given key
deleteKey(root, key);
// Print all words that remain in the Trie
for (string w : words) {
if (search(root, w)) {
cout << w << " ";
}
}
return 0;
}
class TrieNode {
TrieNode[] children;
boolean isEndOfWord;
TrieNode() {
children = new TrieNode[26];
isEndOfWord = false;
}
}
public class GFG {
// Check whether a node has any children
static boolean isItFreeNode(TrieNode node) {
for (int i = 0; i < 26; i++) {
if (node.children[i] != null) {
return false;
}
}
return true;
}
// Recursively delete a key from the Trie
static TrieNode deleteHelper(TrieNode node, String key, int depth) {
if (node == null) {
return null;
}
// If we have reached the end of the key
if (depth == key.length()) {
// Key is not present
if (!node.isEndOfWord) {
return node;
}
// Remove the end-of-word mark
node.isEndOfWord = false;
// Delete this node if it has no children
if (depth != 0 && isItFreeNode(node)) {
return null;
}
return node;
}
int index = key.charAt(depth) - 'a';
// Recursively delete the remaining characters
node.children[index] = deleteHelper(
node.children[index], key, depth + 1
);
// Delete the current node if it is no longer needed
if (depth != 0 && !node.isEndOfWord && isItFreeNode(node)) {
return null;
}
return node;
}
static void deleteKey(TrieNode root, String key) {
if (root == null || key.isEmpty()) {
return;
}
deleteHelper(root, key, 0);
}
// Insert a key into the Trie
static void insert(TrieNode root, String key) {
TrieNode curr = root;
for (char ch : key.toCharArray()) {
int index = ch - 'a';
if (curr.children[index] == null) {
curr.children[index] = new TrieNode();
}
curr = curr.children[index];
}
curr.isEndOfWord = true;
}
// Search for a key in the Trie
static boolean search(TrieNode root, String key) {
TrieNode curr = root;
for (char ch : key.toCharArray()) {
int index = ch - 'a';
if (curr.children[index] == null) {
return false;
}
curr = curr.children[index];
}
return curr.isEndOfWord;
}
public static void main(String[] args) {
// Create a Trie
TrieNode root = new TrieNode();
// Insert keys into the Trie
String[] words = {"car", "card", "care", "dog"};
for (String word : words) {
insert(root, word);
}
// Key to delete
String key = "card";
// Delete the given key
deleteKey(root, key);
// Print all words that remain in the Trie
for (String w : words) {
if (search(root, w)) {
System.out.print(w + " ");
}
}
}
}
class TrieNode:
def __init__(self):
self.children = [None] * 26
self.isEndOfWord = False
# Check whether a node has any children
def isItFreeNode(node):
for i in range(26):
if node.children[i] is not None:
return False
return True
# Recursively delete a key from the Trie
def deleteHelper(node, key, depth):
if node is None:
return None
# If we have reached the end of the key
if depth == len(key):
# Key is not present
if not node.isEndOfWord:
return node
# Remove the end-of-word mark
node.isEndOfWord = False
# Delete this node if it has no children
if depth != 0 and isItFreeNode(node):
return None
return node
index = ord(key[depth]) - ord('a')
# Recursively delete the remaining characters
node.children[index] = deleteHelper(
node.children[index], key, depth + 1
)
# Delete the current node if it is no longer needed
if depth != 0 and not node.isEndOfWord and isItFreeNode(node):
return None
return node
def deleteKey(root, key):
if root is None or not key:
return
deleteHelper(root, key, 0)
# Insert a key into the Trie
def insert(root, key):
curr = root
for ch in key:
index = ord(ch) - ord('a')
if curr.children[index] is None:
curr.children[index] = TrieNode()
curr = curr.children[index]
curr.isEndOfWord = True
# Search for a key in the Trie
def search(root, key):
curr = root
for ch in key:
index = ord(ch) - ord('a')
if curr.children[index] is None:
return False
curr = curr.children[index]
return curr.isEndOfWord
if __name__ == "__main__":
# Create a Trie
root = TrieNode()
# Insert keys into the Trie
words = ["car", "card", "care", "dog"]
for word in words:
insert(root, word)
# Key to delete
key = "card"
# Delete the given key
deleteKey(root, key)
# Print all words that remain in the Trie
for w in words:
if search(root, w):
print(w, end=" ")
using System;
class TrieNode {
public TrieNode[] children;
public bool isEndOfWord;
public TrieNode() {
children = new TrieNode[26];
isEndOfWord = false;
}
}
class GFG {
// Check whether a node has any children
static bool isItFreeNode(TrieNode node) {
for (int i = 0; i < 26; i++) {
if (node.children[i] != null) {
return false;
}
}
return true;
}
// Recursively delete a key from the Trie
static TrieNode deleteHelper(TrieNode node, string key, int depth) {
if (node == null) {
return null;
}
// If we have reached the end of the key
if (depth == key.Length) {
// Key is not present
if (!node.isEndOfWord) {
return node;
}
// Remove the end-of-word mark
node.isEndOfWord = false;
// Delete this node if it has no children
if (depth != 0 && isItFreeNode(node)) {
return null;
}
return node;
}
int index = key[depth] - 'a';
// Recursively delete the remaining characters
node.children[index] = deleteHelper(
node.children[index], key, depth + 1
);
// Delete the current node if it is no longer needed
if (depth != 0 && !node.isEndOfWord && isItFreeNode(node)) {
return null;
}
return node;
}
static void deleteKey(TrieNode root, string key) {
if (root == null || string.IsNullOrEmpty(key)) {
return;
}
deleteHelper(root, key, 0);
}
// Insert a key into the Trie
static void insert(TrieNode root, string key) {
TrieNode curr = root;
foreach (char ch in key) {
int index = ch - 'a';
if (curr.children[index] == null) {
curr.children[index] = new TrieNode();
}
curr = curr.children[index];
}
curr.isEndOfWord = true;
}
// Search for a key in the Trie
static bool search(TrieNode root, string key) {
TrieNode curr = root;
foreach (char ch in key) {
int index = ch - 'a';
if (curr.children[index] == null) {
return false;
}
curr = curr.children[index];
}
return curr.isEndOfWord;
}
static void Main(string[] args) {
// Create a Trie
TrieNode root = new TrieNode();
// Insert keys into the Trie
string[] words = {"car", "card", "care", "dog"};
foreach (string word in words) {
insert(root, word);
}
// Key to delete
string key = "card";
// Delete the given key
deleteKey(root, key);
// Print all words that remain in the Trie
foreach (string w in words) {
if (search(root, w)) {
Console.Write(w + " ");
}
}
}
}
class TrieNode {
constructor() {
this.children = new Array(26).fill(null);
this.isEndOfWord = false;
}
}
// Check whether a node has any children
function isItFreeNode(node) {
for (let i = 0; i < 26; i++) {
if (node.children[i] !== null) {
return false;
}
}
return true;
}
// Recursively delete a key from the Trie
function deleteHelper(node, key, depth) {
if (node === null) {
return null;
}
// If we have reached the end of the key
if (depth === key.length) {
// Key is not present
if (!node.isEndOfWord) {
return node;
}
// Remove the end-of-word mark
node.isEndOfWord = false;
// Delete this node if it has no children
if (depth !== 0 && isItFreeNode(node)) {
return null;
}
return node;
}
let index = key.charCodeAt(depth) - 97;
// Recursively delete the remaining characters
node.children[index] = deleteHelper(
node.children[index], key, depth + 1
);
// Delete the current node if it is no longer needed
if (depth !== 0 && !node.isEndOfWord && isItFreeNode(node)) {
return null;
}
return node;
}
function deleteKey(root, key) {
if (root === null || key.length === 0) {
return;
}
deleteHelper(root, key, 0);
}
// Insert a key into the Trie
function insert(root, key) {
let curr = root;
for (let ch of key) {
let index = ch.charCodeAt(0) - 97;
if (curr.children[index] === null) {
curr.children[index] = new TrieNode();
}
curr = curr.children[index];
}
curr.isEndOfWord = true;
}
// Search for a key in the Trie
function search(root, key) {
let curr = root;
for (let ch of key) {
let index = ch.charCodeAt(0) - 97;
if (curr.children[index] === null) {
return false;
}
curr = curr.children[index];
}
return curr.isEndOfWord;
}
// Driver code
let root = new TrieNode();
// Insert keys into the Trie
let words = ["car", "card", "care", "dog"];
for (let word of words) {
insert(root, word);
}
// Key to delete
let key = "card";
deleteKey(root, keyToDelete);
// Print all words that remain in the Trie
for (let w of words) {
if (search(root, w)) {
process.stdout.write(w + " ");
}
}
Output
car care dog
Time Complexity: O(n), where n is the length of the key. Each character is visited once during the deletion process.
Auxiliary Space: O(n), due to the recursive call stack, where n is the length of the key.