Open In App

Maximum XOR Queries With an Element From Array

Last Updated : 18 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given an array arr[] of size n containing non-negative integers and also given a list of q queries in a 2D array queries[][], where each query is of the form [xi, mi]. For each query, you need to find the maximum value of (xi XOR arr[j]) such that arr[j] is less than or equal to mi.

In simple terms, you're looking for the number in arr (that is not bigger than mi) which, when XOR with xi, gives the highest possible result.

If no such number exists (i.e., all elements in arr are greater than mi), return -1 for that query.
Return an array, where ith index stores the result for the ith query.

Examples

Input: arr[] = [0, 1, 2, 3, 4], queries[][] = [[3, 1], [1, 3], [5, 6]]
Output: [3, 3, 7]
Explanation: 

  • For the query [3, 1]:
    Only elements in arr that are ≤ 1 are 0 and 1.
    3 XOR 0 = 3 and 3 XOR 1 = 2.
    So, the maximum result is 3.
  • For the query [1, 3]:
    Elements ≤ 3 in arr are 0, 1, 2, 3
    1 XOR 2 = 3 gives the highest value.
    So, the maximum result is 3.
  • For the query [5, 6]:
    All elements of arr are ≤ 6.
    5 XOR 2 = 7 gives the highest value.
    So, the maximum result is 7.

Input: arr[] = [5, 2, 4, 6, 6, 3], queries[][] = [[12, 4], [8, 1], [6, 3]]
Output: [15, -1, 5]
Explanation:

  • For the query [12, 4]:
        Elements in arr that are ≤ 4 are 2, 4, and 3.
        Maximum result is 12 XOR 3 = 15.
  • For the query [8, 1]:
        There is no element in arr that is ≤ 1.
        So, the result is -1.
  • For the query [6, 3]:
        Elements in arr that are ≤ 3 are 2 and 3.
        Maximum result is 6 XOR 3 = 5.

[Naive Approach] Check All possible Combination - O(n*q) Time and O(1) Space

For each query, we loop through the array and verify if arr[i] falls within the given limit. If it does, we calculate the XOR of arr[i] and xi, and continually update the maximum XOR value encountered throughout the iteration.

C++
#include <bits/stdc++.h>
using namespace std;

// Function to find the maximum XOR for each query
vector<int> maxXor(vector<int> &arr, vector<vector<int>> &queries){
    
    // Number of elements in the array
    int n = arr.size();  
    
    // Number of queries
    int q = queries.size();
    
    // Initialize the result vector with -1
    vector<int> result(q, -1);

    // Loop over each query
    for (int i = 0; i < q; i++){
        
        // Value to XOR with
        int xi = queries[i][0];
        
        // Maximum allowed value from arr
        int mi = queries[i][1];   
        
        // Track the maximum XOR for this query
        int maxXor = -1;    
        
        // Check all elements in arr
        for (int j = 0; j < n; j++) {
            
            // Only consider elements less than or equal to mi
            if (arr[j] <= mi){
                
                // Update maxXor if this XOR is greater than 
                // the current maximum
                maxXor = max(maxXor, arr[j] ^ xi);
            }
        }

        // Store the result for this query
        result[i] = maxXor;
    }

    // Return results for all queries
    return result;
}

int main(){
    
    vector<int> arr = {0, 1, 2, 3, 4};
    
    vector<vector<int>> queries = {{3, 1}, {1, 3}, {5, 6}};
    
    vector<int> ans = maxXor(arr, queries);
    
    // Output the results
    for(auto it: ans){
        cout << it << ' ';
    }

    return 0;
}
Java
import java.util.*;

class GfG {

    // Function to find the maximum XOR for each query
     static ArrayList<Integer> maxXor(int[] arr, int[][] queries) {
        int n = arr.length;
        int q = queries.length;

        ArrayList<Integer> result = new ArrayList<>(Collections.nCopies(q, -1));

        for (int i = 0; i < q; i++) {
            
            // Value to XOR with
            int xi = queries[i][0];
            
            // Maximum allowed value from arr
            int mi = queries[i][1];
            
            int maxXor = -1;

            for (int j = 0; j < n; j++) {
                if (arr[j] <= mi) {
                    maxXor = Math.max(maxXor, arr[j] ^ xi);
                }
            }

            result.set(i, maxXor);
        }

        return result;
    }

    public static void main(String[] args) {
        int[] arr = {0, 1, 2, 3, 4};
        int[][] queries = {{3, 1}, {1, 3}, {5, 6}};

        ArrayList<Integer> ans = maxXor(arr, queries);

        for (int x : ans) {
            System.out.print(x + " ");
        }
    }
}
Python
def maxXor(arr, queries):
    
    # Number of elements in the array
    n = len(arr)
    
    # Number of queries
    q = len(queries)

    # Initialize the result list with -1 (default for no valid elements)
    result = [-1] * q

    # Loop over each query
    for i in range(q):
        # Value to XOR with and max limit
        xi, mi = queries[i]  
        maxXor = -1

        # Check all elements in arr
        for j in range(n):
            if arr[j] <= mi:
                maxXor = max(maxXor, arr[j] ^ xi)

        # Store result
        result[i] = maxXor

    return result

if __name__ == "__main__":
    arr = [0, 1, 2, 3, 4]
    queries = [[3, 1], [1, 3], [5, 6]]

    ans = maxXor(arr, queries)

    # Print the results
    print(*ans)
C#
using System;
using System.Collections.Generic;

class GfG{
    
    // Function to find the maximum XOR for each query
    static List<int> maxXor(int[] arr, int[,] queries){
        int n = arr.Length;
        int q = queries.GetLength(0);

        List<int> result = new List<int>(new int[q]);
        for (int i = 0; i < q; i++) result[i] = -1;

        for (int i = 0; i < q; i++){ 
            
            // Value to XOR with
            int xi = queries[i, 0]; 
            
            // Maximum allowed value from arr
            int mi = queries[i, 1]; 
            
            int maxXor = -1;

            for (int j = 0; j < n; j++){
                if (arr[j] <= mi){
                    maxXor = Math.Max(maxXor, arr[j] ^ xi);
                }
            }

            result[i] = maxXor;
        }

        return result;
    }

    static void Main(){
        int[] arr = {0, 1, 2, 3, 4};
        int[,] queries = {{3, 1}, {1, 3}, {5, 6}};

        List<int> ans = maxXor(arr, queries);

        foreach (int x in ans){
            Console.Write(x + " ");
        }
    }
}
JavaScript
function maxXor(arr, queries) {
    const n = arr.length;
    const q = queries.length;
    
    // Initialize the result array with -1
    const result = new Array(q).fill(-1);

    // Loop through each query
    for (let i = 0; i < q; i++) {
        const [xi, mi] = queries[i]; 
        let maxXor = -1;

        // Check all elements in arr
        for (let j = 0; j < n; j++) {
            if (arr[j] <= mi) {
                maxXor = Math.max(maxXor, arr[j] ^ xi);
            }
        }

        result[i] = maxXor;
    }

    return result;
}

// Driver code
const arr = [0, 1, 2, 3, 4];
const queries = [[3, 1], [1, 3], [5, 6]];

const ans = maxXor(arr, queries);

// Output the results
console.log(...ans);

Output
3 3 7 

[Expected Approach] Using Trie - O(n*log⁡n + q*log⁡q) Time and O(n + q) Space

We use a Trie in this problem to efficiently store and search for array elements based on their binary representation. The Trie allows us to quickly compute the maximum XOR for a given query by traversing the bits of the numbers, which reduces the time complexity from O(n*q) to O(n*log⁡n + q*log⁡q). The Trie structure enables fast insertion and retrieval of elements, making it ideal for maximizing the XOR in O(32) time per query. This optimization is key for handling large inputs efficiently

First, we sort both the input array and the queries by their “maximum allowed” value mim_imi​. Then we process the queries in ascending order of mim_imi​, maintaining a single pointer into the sorted array:

  • Incremental Trie–Building
    As we move from one query to the next, we insert into the Trie all array elements ≤mi that haven’t yet been added. Each element is inserted exactly once, in O(32) bit‑steps.
  • Constant‑Time XOR Lookup
    Once the Trie contains only those elements allowed by the current query, we compute max⁡(arr[j]  XOR  xi)by a single 32‑bit traversal of the Trie, again in O(32).
C++
#include <bits/stdc++.h>
using namespace std;

// Trie Node class
class node {
public:
    node *left;
    node *right;
};

// Trie class to insert numbers and find maximum XOR
class trie {
    node *root;

public:
    // Constructor to initialize the root
    trie() {
        root = new node();
    }

    // Insert a number into the Trie (bit by bit from MSB to LSB)
    void insert(int n) {
        node *temp = root;
        for (int i = 31; i >= 0; i--) {
            int bit = (n >> i) & 1;
            if (bit == 0) {
                if (temp->left == NULL)
                    temp->left = new node();
                temp = temp->left;
            } else {
                if (temp->right == NULL)
                    temp->right = new node();
                temp = temp->right;
            }
        }
    }

    // Helper function to find the maximum XOR value with a given number
    int xorHelper(int value) {
        int curr = 0;
        node *temp = root;

        for (int j = 31; j >= 0; j--) {
            int bit = (value >> j) & 1;

            // Prefer the opposite bit for maximizing XOR
            if (bit == 0) {
                if (temp->right != NULL) {
                    temp = temp->right;
                    curr += (1 << j); 
                } else {
                    temp = temp->left;
                }
            } else {
                if (temp->left != NULL) {
                    temp = temp->left;
                    curr += (1 << j); 
                } else {
                    temp = temp->right;
                }
            }
        }

        return curr;
    }
};

// Function to answer all max XOR queries
vector<int> maxXor(vector<int> &arr, vector<vector<int>> &queries) {
    int n = arr.size(), q = queries.size();
    vector<int> ans(q); // Result array
    vector<vector<int>> qry;
    
    // Sort array for efficient traversal
    sort(arr.begin(), arr.end()); 

    // Transform queries: [mi, xi, index] for sorting by mi
    for (int i = 0; i < q; i++) {
        qry.push_back({queries[i][1], queries[i][0], i});
    }

    // Sort queries by mi (max value constraint)
    sort(qry.begin(), qry.end());

    int j = 0;
    trie tree;

    // Process each query in increasing order of mi
    for (int i = 0; i < q; i++) {
        
        // Insert all array elements <= mi into the Trie
        while (j < arr.size() && arr[j] <= qry[i][0]) {
            tree.insert(arr[j++]);
        }

        // If no elements <= mi, answer is -1
        if (j == 0)
            ans[qry[i][2]] = -1;
        else
            // Get max XOR with xi using Trie
            ans[qry[i][2]] = tree.xorHelper(qry[i][1]);
    }

    return ans;
}

int main() {
    vector<int> arr = {0, 1, 2, 3, 4};

    // Sample queries: each query is {xi, mi}
    vector<vector<int>> queries = {{3, 1}, {1, 3}, {5, 6}};

    // Get answers for the queries
    vector<int> ans = maxXor(arr, queries);

    // Output the results
    for (auto it : ans) {
        cout << it << ' ';
    }

    return 0;
}
Java
import java.util.*;

class Node {
    Node left, right;
}

class Trie {
    Node root;

    public Trie() {
        root = new Node();
    }

    // Insert number into Trie
    public void insert(int n) {
        Node temp = root;
        for (int i = 31; i >= 0; i--) {
            int bit = (n >> i) & 1;
            if (bit == 0) {
                if (temp.left == null)
                    temp.left = new Node();
                temp = temp.left;
            } else {
                if (temp.right == null)
                    temp.right = new Node();
                temp = temp.right;
            }
        }
    }

    // Find max XOR with given value
    public int xorHelper(int value) {
        Node temp = root;
        int curr = 0;

        for (int j = 31; j >= 0; j--) {
            int bit = (value >> j) & 1;

            if (bit == 0) {
                if (temp.right != null) {
                    temp = temp.right;
                    curr += (1 << j);
                } else {
                    temp = temp.left;
                }
            } else {
                if (temp.left != null) {
                    temp = temp.left;
                    curr += (1 << j);
                } else {
                    temp = temp.right;
                }
            }
        }

        return curr;
    }
}

 class GfG {

     static ArrayList<Integer> maxXor(int[] arr, int[][] queries) {
        int n = arr.length, q = queries.length;
        ArrayList<Integer> ans = new ArrayList<>(Collections.nCopies(q, 0));
        ArrayList<int[]> qry = new ArrayList<>();

        Arrays.sort(arr); 

        // Add [mi, xi, index] format for each query
        for (int i = 0; i < q; i++) {
            qry.add(new int[]{queries[i][1], queries[i][0], i});
        }

        // Sort queries by mi
        qry.sort(Comparator.comparingInt(a -> a[0]));

        Trie tree = new Trie();
        int j = 0;

        for (int i = 0; i < q; i++) {
            int mi = qry.get(i)[0];
            int xi = qry.get(i)[1];
            int idx = qry.get(i)[2];

            while (j < n && arr[j] <= mi) {
                tree.insert(arr[j++]);
            }

            if (j == 0) {
                ans.set(idx, -1);
            } else {
                ans.set(idx, tree.xorHelper(xi));
            }
        }

        return ans;
    }

    public static void main(String[] args) {
        int[] arr = {0, 1, 2, 3, 4};
        int[][] queries = {{3, 1}, {1, 3}, {5, 6}};

        ArrayList<Integer> ans = maxXor(arr, queries);

        for (int val : ans) {
            System.out.print(val + " ");
        }
    }
}
Python
# Trie Node class
class node:
    def __init__(self):
        
        # Represents bit 0
        self.left = None 
        
        # Represents bit 1
        self.right = None 

# Trie class to insert numbers and find maximum XOR
class trie:
    def __init__(self):
        self.root = node()

    # Insert a number into the Trie (bit by bit from MSB to LSB)
    def insert(self, n):
        temp = self.root
        for i in range(31, -1, -1):
            bit = (n >> i) & 1
            if bit == 0:
                if temp.left is None:
                    temp.left = node()
                temp = temp.left
            else:
                if temp.right is None:
                    temp.right = node()
                temp = temp.right

    # Helper function to find the maximum XOR value with a given number
    def xorHelper(self, value):
        curr = 0
        temp = self.root

        for j in range(31, -1, -1):
            bit = (value >> j) & 1

            # Prefer the opposite bit for maximizing XOR
            if bit == 0:
                if temp.right is not None:
                    temp = temp.right
                    curr += (1 << j)
                else:
                    temp = temp.left
            else:
                if temp.left is not None:
                    temp = temp.left
                    curr += (1 << j)
                else:
                    temp = temp.right

        return curr

# Function to answer all max XOR queries
def maxXor(arr, queries):
    n = len(arr)
    q = len(queries)
    
    # Result array
    ans = [-1] * q  
    qry = []

    # Sort the array for efficient Trie population
    arr.sort()

    # Transform queries: [mi, xi, index] for sorting by mi
    for i in range(q):
        qry.append([queries[i][1], queries[i][0], i])

    # Sort queries by mi (max value constraint)
    qry.sort()

    j = 0
    tree = trie()

    # Process each query in increasing order of mi
    for i in range(q):
        
        # Insert all array elements <= mi into the Trie
        while j < len(arr) and arr[j] <= qry[i][0]:
            tree.insert(arr[j])
            j += 1

        # If no elements <= mi, answer is -1
        if j == 0:
            ans[qry[i][2]] = -1
        else:
            # Get max XOR with xi using Trie
            ans[qry[i][2]] = tree.xorHelper(qry[i][1])

    return ans
    
if __name__ == "__main__":
    arr = [0, 1, 2, 3, 4]

    # Sample queries: each query is [xi, mi]
    queries = [[3, 1], [1, 3], [5, 6]]

    # Get answers for the queries
    ans = maxXor(arr, queries)

    # Output the results
    print(*ans)
C#
using System;
using System.Collections.Generic;

class Node {
    public Node Left;
    public Node Right;
}

class Trie {
    private Node root;

    public Trie() {
        root = new Node();
    }

    // Insert a number into the Trie (bit by bit from MSB to LSB)
    public void Insert(int n) {
        Node temp = root;
        for (int i = 31; i >= 0; i--) {
            int bit = (n >> i) & 1;
            if (bit == 0) {
                if (temp.Left == null)
                    temp.Left = new Node();
                temp = temp.Left;
            }
            else {
                if (temp.Right == null)
                    temp.Right = new Node();
                temp = temp.Right;
            }
        }
    }

    // Helper function to find the maximum XOR value with a given number
    public int XorHelper(int value) {
        int curr = 0;
        Node temp = root;

        for (int j = 31; j >= 0; j--) {
            int bit = (value >> j) & 1;

            // Prefer the opposite bit for maximizing XOR
            if (bit == 0) {
                if (temp.Right != null) {
                    temp = temp.Right;
                    curr += (1 << j);
                }
                else {
                    temp = temp.Left;
                }
            }
            else {
                if (temp.Left != null) {
                    temp = temp.Left;
                    curr += (1 << j);
                }
                else {
                    temp = temp.Right;
                }
            }
        }

        return curr;
    }
}

class GfG {
    
  static List<int> maxXor(int[] arr, int[,] queries) {
      
        int n = arr.Length, q = queries.GetLength(0);
        List<int> ans = new List<int>(new int[q]);
        List<List<int>> qry = new List<List<int>>();

        // Sort the array for efficient Trie population
        Array.Sort(arr);

        // Transform queries: [mi, xi, index] for sorting by mi
        for (int i = 0; i < q; i++) {
            qry.Add(new List<int> { queries[i, 1], queries[i, 0], i });
        }

        // Sort queries by mi (max value constraint)
        qry.Sort((a, b) => a[0].CompareTo(b[0]));

        int j = 0;
        Trie tree = new Trie();

        // Process each query in increasing order of mi
        for (int i = 0; i < q; i++) {
            
            // Insert all array elements <= mi into the Trie
            while (j < arr.Length && arr[j] <= qry[i][0]) {
                tree.Insert(arr[j++]);
            }

            // If no elements <= mi, answer is -1
            if (j == 0)
                ans[qry[i][2]] = -1;
            else
                // Get max XOR with xi using Trie
                ans[qry[i][2]] = tree.XorHelper(qry[i][1]);
        }

        return ans;
    }

    static void Main() {
        
        int[] arr = { 0, 1, 2, 3, 4 };

        // Sample queries: each query is [xi, mi]
        int[,] queries = {
            { 3, 1 },
            { 1, 3 },
            { 5, 6 }
        };

        // Get answers for the queries
        List<int> ans = maxXor(arr, queries);

        // Output the results
        foreach (var it in ans) {
            Console.Write(it + " ");
        }
    }
}
JavaScript
class Node {
    constructor() {
        this.left = null;
        this.right = null;
    }
}

class Trie {
    constructor() {
        this.root = new Node();
    }

    // Insert a number into the Trie (bit by bit from MSB to LSB)
    insert(n) {
        let temp = this.root;
        for (let i = 31; i >= 0; i--) {
            let bit = (n >> i) & 1;
            if (bit === 0) {
                if (temp.left === null) {
                    temp.left = new Node();
                }
                temp = temp.left;
            } else {
                if (temp.right === null) {
                    temp.right = new Node();
                }
                temp = temp.right;
            }
        }
    }

    // Helper function to find the maximum XOR value with a given number
    xorHelper(value) {
        let curr = 0;
        let temp = this.root;

        for (let j = 31; j >= 0; j--) {
            let bit = (value >> j) & 1;

            // Prefer the opposite bit for maximizing XOR
            if (bit === 0) {
                if (temp.right !== null) {
                    temp = temp.right;
                    curr += (1 << j);
                } else {
                    temp = temp.left;
                }
            } else {
                if (temp.left !== null) {
                    temp = temp.left;
                    curr += (1 << j);
                } else {
                    temp = temp.right;
                }
            }
        }

        return curr;
    }
}

// Function to answer all max XOR queries
function maxXor(arr, queries) {
    let n = arr.length, q = queries.length;
    let ans = new Array(q); // Result array
    let qry = [];
    
    // Sort array for efficient traversal
    arr.sort((a, b) => a - b);

    // Transform queries: [mi, xi, index] for sorting by mi
    for (let i = 0; i < q; i++) {
        qry.push([queries[i][1], queries[i][0], i]);
    }

    // Sort queries by mi (max value constraint)
    qry.sort((a, b) => a[0] - b[0]);

    let j = 0;
    let tree = new Trie();

    // Process each query in increasing order of mi
    for (let i = 0; i < q; i++) {
        // Insert all array elements <= mi into the Trie
        while (j < arr.length && arr[j] <= qry[i][0]) {
            tree.insert(arr[j++]);
        }

        // If no elements <= mi, answer is -1
        if (j === 0)
            ans[qry[i][2]] = -1;
        else
            // Get max XOR with xi using Trie
            ans[qry[i][2]] = tree.xorHelper(qry[i][1]);
    }

    return ans;
}

// Test the function with sample input
let arr = [0, 1, 2, 3, 4];

// Sample queries: each query is [xi, mi]
let queries = [
    [3, 1],
    [1, 3],
    [5, 6]
];

// Get answers for the queries
let ans = maxXor(arr, queries);

// Output the results
console.log(ans.join(' '));

Output
3 3 7 



Next Article
Article Tags :
Practice Tags :

Similar Reads