Open In App

Maximum XOR of Two Nodes in a Tree

Last Updated : 08 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a binary tree, where each node has a binary value, design an efficient algorithm to find the maximum XOR of any two node values in the tree.

Examples:

Input:

        1
      /   \
    2     3
   / \   /
4   5 6
Output: 7
Explanation: 6 XOR 1 = 7

Input:

       1
     /   \
   5     2
  /       \
9         3

Output: 12
Explanation: 9 XOR 5 = 12

Naive Approach: A simple solution is to generate all pairs, find their XOR values, and finally return the maximum XOR value. But its time and space complexity will be very high.

Time Complexity: O(N2) where N is the number of nodes in the given tree.

Auxiliary Space: O(1)

Efficient Approach: We can use a trie-based solution for this problem and utilize bit manipulation to efficiently store and retrieve values from the trie.

Trie Representation of Example 1:

            (root)
             /   \
           0     1
          / \   / \
       0   1 1   0
     /     |     \
  0      1      0

Here, each node of the Trie has two children, 0 and 1. Each level of the Trie corresponds to a bit in the binary representation of the numbers. The root node corresponds to the most significant bit, and the leaf nodes correspond to the least significant bit. The numbers in the above example have the following binary representation:

  • 1 = 001
  • 2 = 010
  • 3 = 011
  • 4 = 100
  • 5 = 101
  • 6 = 110

Thus, the Trie structure can be represented in the form of bits of nodes 0 and 1 as follows:

Bitwise representation of trie:

  • Level 2:  0   1
  • Level 1:  0   1   1   0
  • Level 0:  0   1   0   1   1   0

Idea/Intuition:

  • Construct a trie from the binary representation of the node values in the tree, where each node in the trie corresponds to a bit in the binary representation and the path from the root of the trie to a leaf node represents the binary value of a node in the tree.
  • Starting from the most significant bit, traverse the trie to find a pair of node values that have different bits at the current position. If such a pair exists, it contributes to the maximum XOR.
  • To find the pair, check if both 0 and 1 child nodes exist at the current position. If they do, continue the search in the corresponding child node with the opposite bit. If only one child node exists, continue the search in that node.
  • Repeat the above step for all the bits, updating the XOR value with the corresponding bit value each time.
  • Return the final XOR value as the result.

Note: The trie can be constructed efficiently using a recursive approach that traverses the tree in a post-order manner and inserts each node value into the trie as it is processed.

Steps to follow to implement the approach:

  • A Trie data structure is defined, which is used to store the binary representation of each number in the tree.
  • The insert() function of the Trie is used to insert the binary representation of each number in the tree into the Trie.
  • The findMaxXOR() function of the Trie is used to find the maximum XOR of any two numbers in the Trie.
  • A Solution class is defined, which has two member functions:
    • constructTrie() function is a recursive function that constructs the Trie from the given binary tree.
    • findMaximumXOR() function is used to find the maximum XOR of any two node values in the given binary tree.
  • In the main() function, a binary tree is created and a Solution object is created to find the maximum XOR of any two node values in the tree.
  • The findMaximumXOR() function of the Solution object is called, which first constructs the Trie from the given tree and then iterates over each node in the tree to find the maximum XOR.
  • Finally, the maximum XOR of any two node values in the binary tree is printed to the console.

Below is the implementation of the above approach:

C++




// CPP code for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Class definition for TrieNode
class TrieNode {
public:
    TrieNode* children[2];
    TrieNode()
    {
        // Initializing children list
        // with two elements as NULL.
        children[0] = children[1] = NULL;
    }
};
 
// Class definition for Trie
class Trie {
public:
    TrieNode* root;
    Trie()
    {
 
        // Initializing root node
        // of the Trie
        root = new TrieNode();
    }
    void insert(int num)
    {
 
        // Starting from the root node
        TrieNode* node = root;
 
        // Iterating over each bit of
        // the number in reverse order
        for (int i = 31; i >= 0; i--) {
            // Get the ith bit
            int bit = (num >> i) & 1;
 
            // If the bit is not present
            // in the children, add a
            // new TrieNode
            if (!node->children[bit]) {
                node->children[bit] = new TrieNode();
            }
 
            // Move to the next node
            node = node->children[bit];
        }
    }
    int findMaxXOR(int num)
    {
 
        // Starting from the root node
        TrieNode* node = root;
        int maxXor = 0;
 
        // Iterating over each bit of
        // the number in reverse order.
        for (int i = 31; i >= 0; i--) {
 
            // Get the ith bit
            int bit = (num >> i) & 1;
            // If the complement of the
            // current bit is present,
            // add it to the maxXor and
            // move to that node.
            if (node->children[bit ^ 1]) {
                maxXor = (maxXor << 1) | 1;
                node = node->children[bit ^ 1];
            }
 
            // If the complement is not
            // present, move to the node
            // with the current bit
            else {
                maxXor = maxXor << 1;
                node = node->children[bit];
            }
        }
 
        // Return the maximum XOR
        return maxXor;
    }
};
 
// Class definition for TreeNode
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x)
        : val(x), left(NULL), right(NULL)
    {
    }
};
 
// Class definition for Solution
class Solution {
public:
    Trie trie;
    void constructTrie(TreeNode* node)
    {
 
        // Recursively construct Trie
        // for each node in the tree
        if (!node) {
            return;
        }
        trie.insert(node->val);
        constructTrie(node->left);
        constructTrie(node->right);
    }
    int findMaximumXOR(TreeNode* root)
    {
 
        // Construct Trie from
        // the given tree
        constructTrie(root);
        int maxXor = 0;
        TreeNode* node = root;
 
        // Iterate over each node
        // in the tree
        while (node) {
 
            // Find the maximum XOR for
            // the current node and update
            // maxXor if it's greater than
            // the current maxXor
            maxXor
                = max(maxXor, trie.findMaxXOR(node->val));
 
            // Move to the next node,
            // either to the left
            // or right child
            node = node->left ? node->left : node->right;
        }
 
        // Return the maximum XOR
        return maxXor;
    }
};
 
// Driver's code.
int main()
{
 
    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);
    root->left->left = new TreeNode(4);
    root->left->right = new TreeNode(5);
    root->right->left = new TreeNode(6);
 
    Solution s;
 
    // Function Call
    int result = s.findMaximumXOR(root);
    cout << "Maximum XOR: " << result << endl;
 
    return 0;
}


Java




// Java code to implement the above approach.
import java.util.*;
 
// Class definition for TrieNode
class TrieNode {
    TrieNode[] children;
 
    public TrieNode()
    {
        // Initializing children list with two elements
        // (null)
        children = new TrieNode[2];
    }
}
 
// Class definition for Trie
class Trie {
    TrieNode root;
 
    public Trie()
    {
        // Initializing root node of the Trie
        root = new TrieNode();
    }
 
    public void insert(int num)
    {
        // Starting from the root node
        TrieNode node = root;
        // Iterating over each bit of the number in reverse
        // order
        for (int i = 31; i >= 0; i--) {
            // Get the ith bit
            int bit = (num >>> i) & 1;
            // If the bit is not present in the children,
            // add a new TrieNode
            if (node.children[bit] == null) {
                node.children[bit] = new TrieNode();
            }
            // Move to the next node
            node = node.children[bit];
        }
    }
 
    public int findMaxXOR(int num)
    {
        // Starting from the root node
        TrieNode node = root;
        int maxXOR = 0;
        // Iterating over each bit of the number in reverse
        // order
        for (int i = 31; i >= 0; i--) {
            // Get the ith bit
            int bit = (num >>> i) & 1;
            // If the complement of the current bit is
            // present, add it to the maxXOR and move to
            // that node
            if (node.children[bit ^ 1] != null) {
                maxXOR = (maxXOR << 1) | 1;
                node = node.children[bit ^ 1];
            }
            // If the complement is not present,
            // move to the node with the current bit
            else {
                maxXOR = maxXOR << 1;
                node = node.children[bit];
            }
        }
        // Return the maximum XOR
        return maxXOR;
    }
}
 
// Class definition for TreeNode
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
 
    public TreeNode(int x)
    {
        // Value of the node
        val = x;
        // Left and right children
        left = null;
        right = null;
    }
}
 
// Class definition for Solution
class Solution {
    Trie trie;
 
    public Solution()
    {
        // Initializing Trie
        trie = new Trie();
    }
 
    public void constructTrie(TreeNode node)
    {
        // Recursively construct Trie for each node in the
        // tree
        if (node == null) {
            return;
        }
        trie.insert(node.val);
        constructTrie(node.left);
        constructTrie(node.right);
    }
 
    public int findMaximumXOR(TreeNode root)
    {
        // Construct Trie from the given tree
        constructTrie(root);
        int maxXOR = 0;
        TreeNode node = root;
        // Iterate over each node in the tree
        while (node != null) {
            // Find the maximum XOR for the current node and
            // update max_xor if it's greater than the
            // current max_xor
            maxXOR = Math.max(maxXOR,
                              trie.findMaxXOR(node.val));
            // Move to the next node, either to the left or
            // right child
            if (node.right != null) {
                node = node.right;
            }
            else {
                node = node.left;
            }
        }
        // Return the maximum XOR
        return maxXOR;
    }
 
    public static void main(String[] args)
    {
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        root.left.left = new TreeNode(4);
        root.left.right = new TreeNode(5);
        root.right.left = new TreeNode(6);
        Solution s = new Solution();
        int result = s.findMaximumXOR(root);
        System.out.println("Maximum XOR: " + result);
    }
}
 
// This code is contributed by Susobhan Akhuli


Python3




# Python3 code to implement the above approach.
 
# Class definition for TrieNode
class TrieNode:
    def __init__(self):
        # Initializing children list with two elements (None)
        self.children = [None, None]
 
# Class definition for Trie
class Trie:
    def __init__(self):
        # Initializing root node of the Trie
        self.root = TrieNode()
 
    def insert(self, num):
        # Starting from the root node
        node = self.root
        # Iterating over each bit of the number in reverse order
        for i in range(31, -1, -1):
            # Get the ith bit
            bit = (num >> i) & 1
            # If the bit is not present in the children,
            # add a new TrieNode
            if not node.children[bit]:
                node.children[bit] = TrieNode()
            # Move to the next node
            node = node.children[bit]
 
    def findMaxXOR(self, num):
        # Starting from the root node
        node = self.root
        max_xor = 0
        # Iterating over each bit of the number in reverse order
        for i in range(31, -1, -1):
            # Get the ith bit
            bit = (num >> i) & 1
            # If the complement of the current bit is present,
            # add it to the max_xor and move to that node
            if node.children[bit ^ 1]:
                max_xor = (max_xor << 1) | 1
                node = node.children[bit ^ 1]
            # If the complement is not present,
            # move to the node with the current bit
            else:
                max_xor = max_xor << 1
                node = node.children[bit]
        # Return the maximum XOR
        return max_xor
 
# Class definition for TreeNode
class TreeNode:
    def __init__(self, x):
        # Value of the node
        self.val = x
        # Left and right children
        self.left = None
        self.right = None
 
# Class definition for Solution
class Solution:
    def __init__(self):
        # Initializing Trie
        self.trie = Trie()
 
    def constructTrie(self, node):
        # Recursively construct Trie for each node in the tree
        if not node:
            return
        self.trie.insert(node.val)
        self.constructTrie(node.left)
        self.constructTrie(node.right)
 
    def findMaximumXOR(self, root):
        # Construct Trie from the given tree
        self.constructTrie(root)
        max_xor = 0
        node = root
        # Iterate over each node in the tree
        while node:
            # Find the maximum XOR for the current node and
            # update max_xor if it's greater than the current max_xor
            max_xor = max(max_xor, self.trie.findMaxXOR(node.val))
            # Move to the next node
            node = node.left if node.right else node.right
        # Return the maximum XOR
        return max_xor
 
if __name__ == '__main__':
    root = TreeNode(1)
    root.left = TreeNode(2)
    root.right = TreeNode(3)
    root.left.left = TreeNode(4)
    root.left.right = TreeNode(5)
    root.right.left = TreeNode(6)
    s = Solution()
    result = s.findMaximumXOR(root)
    print("Maximum XOR:", result) # 7
 
# This code is contributed by Susobhan Akhuli


C#




// C# code to implement the above approach.
using System;
 
// Class definition for TrieNode
class TrieNode {
    public TrieNode[] children;
 
    public TrieNode()
    {
        // Initializing children list with two elements
        // (null)
        children = new TrieNode[2];
    }
}
 
// Class definition for Trie
class Trie {
    public TrieNode root;
 
    public Trie()
    {
        // Initializing root node of the Trie
        root = new TrieNode();
    }
 
    public void insert(int num)
    {
        // Starting from the root node
        TrieNode node = root;
        // Iterating over each bit of the number in reverse
        // order
        for (int i = 31; i >= 0; i--) {
            // Get the ith bit
            int bit = (num >> i) & 1;
            // If the bit is not present in the children,
            // add a new TrieNode
            if (node.children[bit] == null) {
                node.children[bit] = new TrieNode();
            }
            // Move to the next node
            node = node.children[bit];
        }
    }
 
    public int findMaxXOR(int num)
    {
        // Starting from the root node
        TrieNode node = root;
        int max_xor = 0;
        // Iterating over each bit of the number in reverse
        // order
        for (int i = 31; i >= 0; i--) {
            // Get the ith bit
            int bit = (num >> i) & 1;
            // If the complement of the current bit is
            // present, add it to the max_xor and move to
            // that node
            if (node.children[bit ^ 1] != null) {
                max_xor = (max_xor << 1) | 1;
                node = node.children[bit ^ 1];
            }
            // If the complement is not present,
            // move to the node with the current bit
            else {
                max_xor = max_xor << 1;
                node = node.children[bit];
            }
        }
        // Return the maximum XOR
        return max_xor;
    }
}
 
// Class definition for TreeNode
class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;
 
    public TreeNode(int x)
    {
        // Value of the node
        val = x;
        // Left and right children
        left = null;
        right = null;
    }
}
 
// Class definition for Solution
class Solution {
    public Trie trie;
 
    public Solution()
    {
        // Initializing Trie
        trie = new Trie();
    }
 
    public void constructTrie(TreeNode node)
    {
        // Recursively construct Trie for each node in the
        // tree
        if (node == null) {
            return;
        }
        trie.insert(node.val);
        constructTrie(node.left);
        constructTrie(node.right);
    }
 
    // Function to find the maximum XOR of any two node
    // values in the tree
    public int findMaximumXOR(TreeNode root)
    {
        // Construct Trie from the given tree
        constructTrie(root);
        int max_xor = 0;
        TreeNode node = root;
        // Iterate over each node in the tree
        while (node != null) {
            // Find the maximum XOR for the current node and
            // update max_xor if it's greater than the
            // current max_xor
            max_xor = Math.Max(max_xor,
                               trie.findMaxXOR(node.val));
            // Move to the next node
            node = (node.left != null) ? node.left
                                       : node.right;
        }
        // Return the maximum XOR
        return max_xor;
    }
 
    static void Main(string[] args)
    {
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        root.left.left = new TreeNode(4);
        root.left.right = new TreeNode(5);
        root.right.left = new TreeNode(6);
        Solution s = new Solution();
        int result = s.findMaximumXOR(root);
        Console.WriteLine("Maximum XOR: " + result); // 7
    }
}
 
// This code is contributed by Susobhan Akhuli


Javascript




<script>
    // Javascript code to implement the above approach.
     
    // Class definition for TrieNode
    class TrieNode {
        constructor()
        {
            // Initializing children list with two elements
            // (null)
            this.children = [ null, null ];
        }
    }
     
    // Class definition for Trie
    class Trie {
        constructor()
        {
            // Initializing root node of the Trie
            this.root = new TrieNode();
        }
     
        insert(num)
        {
            // Starting from the root node
            let node = this.root;
            // Iterating over each bit of the number in reverse
            // order
            for (let i = 31; i >= 0; i--) {
                // Get the ith bit
                let bit = (num >> i) & 1;
                // If the bit is not present in the children,
                // add a new TrieNode
                if (!node.children[bit]) {
                    node.children[bit] = new TrieNode();
                }
                // Move to the next node
                node = node.children[bit];
            }
        }
     
        findMaxXOR(num)
        {
            // Starting from the root node
            let node = this.root;
            let max_xor = 0;
            // Iterating over each bit of the number in reverse
            // order
            for (let i = 31; i >= 0; i--) {
                // Get the ith bit
                let bit = (num >> i) & 1;
                // If the complement of the current bit is
                // present, add it to the max_xor and move to
                // that node
                if (node.children[bit ^ 1]) {
                    max_xor = (max_xor << 1) | 1;
                    node = node.children[bit ^ 1];
                }
                // If the complement is not present,
                // move to the node with the current bit
                else {
                    max_xor = max_xor << 1;
                    node = node.children[bit];
                }
            }
            // Return the maximum XOR
            return max_xor;
        }
    }
     
    // Class definition for TreeNode
    class TreeNode {
        constructor(x)
        {
            // Value of the node
            this.val = x;
            // Left and right children
            this.left = null;
            this.right = null;
        }
    }
     
    // Class definition for Solution
    class Solution {
        constructor()
        {
            // Initializing Trie
            this.trie = new Trie();
        }
     
        constructTrie(node)
        {
            // Recursively construct Trie for each node in the
            // tree
            if (!node) {
                return;
            }
            this.trie.insert(node.val);
            this.constructTrie(node.left);
            this.constructTrie(node.right);
        }
     
        findMaximumXOR(root)
        {
            // Construct Trie from the given tree
            this.constructTrie(root);
            let max_xor = 0;
            let node = root;
            // Iterate over each node in the tree
            while (node) {
                // Find the maximum XOR for the current node and
                // update max_xor if it's greater than the
                // current max_xor
                max_xor = Math.max(
                    max_xor, this.trie.findMaxXOR(node.val));
                // Move to the next node
                node = node.left ? node.left : node.right;
            }
            // Return the maximum XOR
            return max_xor;
        }
    }
     
    const root
        = new TreeNode(1);
    root.left = new TreeNode(2);
    root.right = new TreeNode(3);
    root.left.left = new TreeNode(4);
    root.left.right = new TreeNode(5);
    root.right.left = new TreeNode(6);
    const s = new Solution();
    const result = s.findMaximumXOR(root);
    document.write("Maximum XOR: ", result); // 7
     
    // This code is contributed by Susobhan Akhuli
</script>


Output

Maximum XOR: 7

Time Complexity: O(N), where N is the number of nodes in the tree since each node in the tree is processed only once during the construction of the trie and the search. 
Auxiliary Space: O(N), since the size of the trie is proportional to the number of nodes in the tree.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads