From f58cfbc904313c65f28b41fd7942580e4da8599a Mon Sep 17 00:00:00 2001 From: Harsh Date: Sun, 13 Oct 2024 19:37:59 +0530 Subject: [PATCH 1/3] K-th Lexographical String added --- Trie/K-th Lexicographical String/Program.c | 78 ++++++++++++++++++++++ Trie/K-th Lexicographical String/Readme.md | 47 +++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 Trie/K-th Lexicographical String/Program.c create mode 100644 Trie/K-th Lexicographical String/Readme.md diff --git a/Trie/K-th Lexicographical String/Program.c b/Trie/K-th Lexicographical String/Program.c new file mode 100644 index 00000000..f4eec907 --- /dev/null +++ b/Trie/K-th Lexicographical String/Program.c @@ -0,0 +1,78 @@ +#include +#include +#include + +#define ALPHABET_SIZE 26 + +// Trie Node Structure +struct TrieNode { + struct TrieNode *children[ALPHABET_SIZE]; // Each node has 26 possible children (for each alphabet letter) + int isEndOfWord; // 1 if this node marks the end of a word +}; + +// Function to create a new Trie node +struct TrieNode *createNode() { + struct TrieNode *node = (struct TrieNode *)malloc(sizeof(struct TrieNode)); + node->isEndOfWord = 0; + for (int i = 0; i < ALPHABET_SIZE; i++) + node->children[i] = NULL; // Initialize all children to NULL + return node; +} + +// Insert a word into the Trie +void insert(struct TrieNode *root, const char *word) { + struct TrieNode *current = root; + while (*word) { + int index = *word - 'a'; // Calculate index for each character (0 for 'a', 1 for 'b', etc.) + if (!current->children[index]) + current->children[index] = createNode(); // Create new node if it doesn't exist + current = current->children[index]; + word++; + } + current->isEndOfWord = 1; // Mark the end of a valid word +} + +// Depth-First Search (DFS) to collect words in lexicographical order +void dfs(struct TrieNode *root, char *currentWord, int level, int *k, char *result) { + if (*k <= 0) return; // If we have found the k-th word, stop searching + + // If this node marks the end of a word, check if it's the k-th word + if (root->isEndOfWord) { + (*k)--; // Decrease k when a valid word is found + if (*k == 0) { + currentWord[level] = '\0'; // Null-terminate the word + strcpy(result, currentWord); // Copy the word to result + return; + } + } + + // Recursively search for children in alphabetical order + for (int i = 0; i < ALPHABET_SIZE; i++) { + if (root->children[i]) { + currentWord[level] = 'a' + i; // Add the current letter to the word + dfs(root->children[i], currentWord, level + 1, k, result); // Go deeper in the Trie + } + } +} +// Function to find the k-th lexicographical string +void findKthWord(struct TrieNode *root, int k, char *result) { + char currentWord[100]; // To store the current word during DFS + dfs(root, currentWord, 0, &k, result); // Start DFS with level 0 +} + +int main() { + struct TrieNode *root = createNode(); // Create the root of the Trie + char *words[] = {"banana", "apple", "grape", "mango", "orange"}; + int n = 5, k = 3; // Example: 5 words and find the 3rd lexicographical word + + // Insert all words into the Trie + for (int i = 0; i < n; i++) + insert(root, words[i]); + + char result[100]; // To store the k-th lexicographical word + findKthWord(root, k, result); // Find the k-th word + + printf("The %d-th lexicographical word is: %s\n", k, result); + return 0; +} +// The 3-th lexicographical word is: grape diff --git a/Trie/K-th Lexicographical String/Readme.md b/Trie/K-th Lexicographical String/Readme.md new file mode 100644 index 00000000..83731063 --- /dev/null +++ b/Trie/K-th Lexicographical String/Readme.md @@ -0,0 +1,47 @@ +## Problem: K-th Lexicographical String in Trie + +### Problem Statement: +Given a set of strings, your task is to find the **k-th lexicographical string** from this set. The lexicographical order is the same as dictionary order, where words are sorted alphabetically. To solve this problem efficiently, we can use a **Trie (Prefix Tree)**, which naturally maintains the order of characters and helps in finding lexicographical order. + +### Approach Overview: +A **Trie (Prefix Tree)** allows us to store words in a hierarchical structure, with each node representing a character. By traversing this Trie in alphabetical order, we can collect the strings in lexicographical order and directly retrieve the k-th word. + +### Steps: + +1. **TrieNode Structure**: + - Each node in the Trie has an array `children[26]` for the lowercase English alphabet (`'a'` to `'z'`). + - `isEndOfWord` marks if the node is the end of a valid word. + - Each node can have 26 possible children, corresponding to each letter. + +2. **Insertion**: + - Each word from the input list is inserted into the Trie, character by character. + - If a node for a character does not exist, a new node is created. + - At the end of each word, mark the final node as an `end of word`. + +3. **Depth-First Search (DFS)** for K-th Lexicographical Word: + - After inserting the words into the Trie, perform a DFS traversal. + - Start at the root node and visit each child in lexicographical order (starting from `'a'` to `'z'`). + - For each word ending node, decrement the counter `k`. + - Once `k` reaches zero, the current string is the desired k-th lexicographical string. + +### Example: +```c +char *words[] = {"banana", "apple", "grape", "mango", "orange"}; +int k = 3; +``` + +1. Insert all the words into the Trie. +2. Traverse the Trie using DFS and find the 3rd lexicographical word. + +**Output**: +``` +The 3rd lexicographical word is: grape +``` +### Key Points: +- The Trie efficiently organizes words such that DFS traversal yields lexicographical order. +- The traversal is designed to visit child nodes from `'a'` to `'z'`, ensuring that words are checked in alphabetical order. +- The algorithm stops when the k-th lexicographical word is found. + +### Time Complexity: +- **Insertion**: Inserting all words into the Trie takes O(n * m) time, where `n` is the number of words, and `m` is the average length of the words. +- **Finding the k-th word**: Traversing the Trie in lexicographical order takes O(26 * m), where `m` is the length of the longest word. \ No newline at end of file From da7b9e2786e37cb815c7e96ffdacbb156129974e Mon Sep 17 00:00:00 2001 From: Harsh Date: Sun, 13 Oct 2024 19:44:20 +0530 Subject: [PATCH 2/3] Maximum XOR of 2 numbers added --- Trie/Maximum XOR/Program.c | 73 ++++++++++++++++++++++++++++++++++++++ Trie/Maximum XOR/Readme.md | 37 +++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 Trie/Maximum XOR/Program.c create mode 100644 Trie/Maximum XOR/Readme.md diff --git a/Trie/Maximum XOR/Program.c b/Trie/Maximum XOR/Program.c new file mode 100644 index 00000000..fc3789b2 --- /dev/null +++ b/Trie/Maximum XOR/Program.c @@ -0,0 +1,73 @@ +#include +#include + +#define BITS 31 // We consider 31 bits for non-negative integers + +// Trie Node Structure for Binary Trie +struct TrieNode { + struct TrieNode *children[2]; // Binary Trie has 2 children (for bit 0 and bit 1) +}; + +// Function to create a new Trie node +struct TrieNode *createBinaryNode() { + struct TrieNode *node = (struct TrieNode *)malloc(sizeof(struct TrieNode)); + node->children[0] = node->children[1] = NULL; // Initialize both children to NULL + return node; +} + +// Insert a number into the binary Trie +void insertBinaryTrie(struct TrieNode *root, int num) { + struct TrieNode *current = root; + for (int i = BITS; i >= 0; i--) { + int bit = (num >> i) & 1; // Get the i-th bit of the number + if (!current->children[bit]) + current->children[bit] = createBinaryNode(); // Create a new node for this bit + current = current->children[bit]; // Move to the child corresponding to this bit + } +} + +// Find the maximum XOR with a given number in the Trie +int findMaxXOR(struct TrieNode *root, int num) { + struct TrieNode *current = root; + int maxXOR = 0; + for (int i = BITS; i >= 0; i--) { + int bit = (num >> i) & 1; // Get the i-th bit of the number + int oppositeBit = 1 - bit; // We want to find the opposite bit to maximize XOR + if (current->children[oppositeBit]) { + maxXOR = (maxXOR << 1) | 1; // If opposite bit exists, add 1 to maxXOR + current = current->children[oppositeBit]; // Move to the opposite bit node + } else { + maxXOR = (maxXOR << 1); // If opposite bit doesn't exist, add 0 to maxXOR + current = current->children[bit]; // Move to the same bit node + } + } + return maxXOR; +} + +// Function to find the maximum XOR of two numbers in an array +int findMaximumXOR(int *nums, int n) { + struct TrieNode *root = createBinaryNode(); // Create the root of the Trie + insertBinaryTrie(root, nums[0]); // Insert the first number into the Trie + + int maxResult = 0; // Variable to store the maximum XOR result + + // Process the rest of the numbers + for (int i = 1; i < n; i++) { + // Find the maximum XOR for the current number and update maxResult + maxResult = (maxResult > findMaxXOR(root, nums[i])) ? maxResult : findMaxXOR(root, nums[i]); + insertBinaryTrie(root, nums[i]); // Insert the current number into the Trie + } + + return maxResult; // Return the maximum XOR found +} + +int main() { + int nums[] = {3, 10, 5, 25, 2, 8}; + int n = sizeof(nums) / sizeof(nums[0]); + + int maxXOR = findMaximumXOR(nums, n); // Find the maximum XOR + printf("Maximum XOR is: %d\n", maxXOR); + + return 0; +} +// Maximum XOR is: 28 \ No newline at end of file diff --git a/Trie/Maximum XOR/Readme.md b/Trie/Maximum XOR/Readme.md new file mode 100644 index 00000000..4d46c1ac --- /dev/null +++ b/Trie/Maximum XOR/Readme.md @@ -0,0 +1,37 @@ +## Problem: Maximum XOR of Two Numbers + +### Problem Statement: +Given an array of non-negative integers, find the maximum XOR of two numbers in the array. The XOR operation between two integers results in a number where each bit is `1` if the corresponding bits of the two numbers differ, and `0` if they are the same. + +### Approach Overview: +To find the maximum XOR of two numbers in an array, we use a **Binary Trie** data structure. This allows us to efficiently compare bits of numbers and attempt to maximize the XOR value. + +### Steps: +1. **Binary TrieNode Structure**: + - Each node has two children: `children[0]` for the bit `0` and `children[1]` for the bit `1`. + - We represent numbers in their binary form (using up to 31 bits). + +2. **Insertion**: + - Each number in the array is inserted into the Trie bit by bit, starting from the most significant bit (MSB). + - New nodes are created as necessary for each bit (`0` or `1`). + +3. **Finding Maximum XOR**: + - For each number, we traverse the Trie and try to maximize the XOR by choosing the opposite bit at each step (e.g., if the current bit is `0`, try to go to `1`, and vice versa). + - The XOR is maximized when we take the opposite bit at each level of the Trie. + +### Example: +```c +int nums[] = {3, 10, 5, 25, 2, 8}; +``` + +1. Insert the numbers into the Trie. +2. For each number, calculate the maximum XOR by traversing the Trie and choosing the path that gives the highest XOR. + +**Output**: +``` +Maximum XOR: 28 +``` + +### Key Points: +- The Binary Trie allows efficient lookup and insertion of binary representations of numbers. +- The XOR is maximized by selecting the opposite bit at each level, ensuring we get the maximum possible value. \ No newline at end of file From 2208a21b3b3e70b23b19980e5e6a2aba3a476aa4 Mon Sep 17 00:00:00 2001 From: Harsh Date: Mon, 14 Oct 2024 20:28:37 +0530 Subject: [PATCH 3/3] Updated --- Trie/LongestCommonPrefix/LongestCommonPrefix.c | 2 +- Trie/LongestCommonPrefix/Readme.md | 1 - Trie/Maximum XOR/Program.c | 1 - Trie/Maximum XOR/Readme.md | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Trie/LongestCommonPrefix/LongestCommonPrefix.c b/Trie/LongestCommonPrefix/LongestCommonPrefix.c index 62ae4d51..3ba61096 100644 --- a/Trie/LongestCommonPrefix/LongestCommonPrefix.c +++ b/Trie/LongestCommonPrefix/LongestCommonPrefix.c @@ -115,4 +115,4 @@ int main() printf("Longest Common Prefix: %s\n", prefix); return 0; -} +} \ No newline at end of file diff --git a/Trie/LongestCommonPrefix/Readme.md b/Trie/LongestCommonPrefix/Readme.md index 6c548006..4890b9a0 100644 --- a/Trie/LongestCommonPrefix/Readme.md +++ b/Trie/LongestCommonPrefix/Readme.md @@ -68,7 +68,6 @@ The longest common prefix we found is `"fl"`. ``` Longest Common Prefix: fl ``` - ### Key Points: - The Trie helps build a common prefix by inserting each word one character at a time and following the path that is shared by all words. diff --git a/Trie/Maximum XOR/Program.c b/Trie/Maximum XOR/Program.c index fc3789b2..3538760e 100644 --- a/Trie/Maximum XOR/Program.c +++ b/Trie/Maximum XOR/Program.c @@ -60,7 +60,6 @@ int findMaximumXOR(int *nums, int n) { return maxResult; // Return the maximum XOR found } - int main() { int nums[] = {3, 10, 5, 25, 2, 8}; int n = sizeof(nums) / sizeof(nums[0]); diff --git a/Trie/Maximum XOR/Readme.md b/Trie/Maximum XOR/Readme.md index 4d46c1ac..b805370c 100644 --- a/Trie/Maximum XOR/Readme.md +++ b/Trie/Maximum XOR/Readme.md @@ -31,7 +31,6 @@ int nums[] = {3, 10, 5, 25, 2, 8}; ``` Maximum XOR: 28 ``` - ### Key Points: - The Binary Trie allows efficient lookup and insertion of binary representations of numbers. - The XOR is maximized by selecting the opposite bit at each level, ensuring we get the maximum possible value. \ No newline at end of file