Open In App

Compute the Bitwise XOR of all Numbers in a Range using JavaScript

The complexity of bitwise XOR computation for all the numbers in a specific range is the most frequent difficulty that many people face during the problem-solving process.

Problem Description: Given two integers, L and R, find the bitwise XOR of all numbers in the inclusive range from L to R. There are several approaches to computing the bitwise XOR of all numbers in a range using JavaScript which are as follows:

Bitwise XOR Property

One optimized approach leverages the XOR operation's properties. XORing a number with itself results in zero (a⊕a=0), and XORing zero with any number gives the same number (a⊕0=a). By exploiting these properties, we can XOR consecutive numbers to cancel each other out, leaving only the XOR of the first and last numbers in the range. This method achieves a time complexity of O(1) by finding the XOR of the first L−1 numbers and the first R numbers, then XORing the results to obtain the final answer.

Example: Let's us consider an example where L=3 and R=6.

The XOR of all numbers from 3 to 6 is calculated as follows:

3⊕4⊕5⊕6=(3⊕4)⊕(5⊕6)
=(7)⊕(3)
=4

Example: To demonstrate computing the bitwise XOR of all numbers in a range using bitwise XOR properties in JavaScript.

function xorRange(L, R) {
    // XOR of numbers from 1 to n
    const xorN = (n) => {
        if (n % 4 === 0) return n;
        if (n % 4 === 1) return 1;
        if (n % 4 === 2) return n + 1;
        return 0;
    };

    // XOR of numbers from 1 to L-1
    const xorLMinusOne = xorN(L - 1);
    // XOR of numbers from 1 to R
    const xorR = xorN(R);

    // XOR of numbers from L to R
    const xorLR = xorLMinusOne ^ xorR;

    return xorLR;
}

const L = 3;
const R = 6;
const result = xorRange(L, R);
console.log(`Bitwise XOR of all numbers from ${L} to ${R} is ${result}`);

Output:

Bitwise XOR of all numbers from 3 to 6 is 4

Time Complexity: O(1), as it does not depend on the size of the range.

Space Complexity: O(1), as we only use a constant amount of additional space regardless of the input size.

Segment Trees

Segment trees are versatile data structures used for storing and querying information about intervals or segments efficiently. We can build a segment tree for the given range and then use it to query the XOR of numbers in the range.

Example: Let us consider an example where we have L=5 and R=15. We will build a segment tree for the range [5, 15] and then query it to find the XOR of numbers from 5 to 15.

// Segment Tree
function updateSegmentTree(tree, index, val, node, start, end) {
    if (start === end) {
        tree[node] ^= val;
        return;
    }

    let mid = Math.floor((start + end) / 2);
    if (index <= mid) {
        updateSegmentTree(tree, index, val, 2 * node, start, mid);
    } else {
        updateSegmentTree(tree, index, val, 2 * node + 1, mid + 1, end);
    }
    tree[node] = tree[2 * node] ^ tree[2 * node + 1];
}

// Query Segment Tree
function querySegmentTree(tree, left, right, node, start, end) {
    if (right < start || left > end) {
        return 0;
    }
    if (left <= start && right >= end) {
        return tree[node];
    }

    let mid = Math.floor((start + end) / 2);
    let leftXor = querySegmentTree(tree, left, right, 2 * node, start, mid);
    let rightXor = querySegmentTree(tree, left, right, 2 * node + 1, mid + 1, end);
    return leftXor ^ rightXor;
}

function xorRange(L, R) {
    // Build Segment Tree
    const n = R - L + 1;
    const tree = new Array(4 * n).fill(0);
    for (let i = L; i <= R; i++) {
        updateSegmentTree(tree, i - L + 1, i, 1, 1, n);
    }

    // Query Segment Tree
    return querySegmentTree(tree, 1, n, 1, 1, n);
}

const L = 5;
const R = 15;
const result = xorRange(L, R);
console.log(`Bitwise XOR of all numbers from ${L} to ${R} is ${result}`);

Output:

Bitwise XOR of all numbers from 5 to 15 is 4

Time Complexity: O(N) , where N is the number of elements in the array. Querying the segment tree takes O(log N) time.

Space Complexity: O(N) for storing the tree structure.

Binary Indexed Trees (Fenwick Trees)

Binary Indexed Trees, also known as Fenwick Trees, are efficient data structures used for querying and updating cumulative frequency or prefix sum arrays. We can modify the Fenwick Tree to support bitwise XOR operations and use it to compute the XOR of numbers in the given range efficiently.

Example: Consider an example where L=3 and R=7. We construct a Fenwick Tree for the given range and then query it to find the XOR of numbers from 3 to 7.

// Update Binary Indexed Tree (Fenwick Tree)
function updateBIT(BIT, index, val) {
    while (index < BIT.length) {
        BIT[index] ^= val;
        index += index & -index;
    }
}

// Query Binary Indexed Tree (Fenwick Tree)
function queryBIT(BIT, index) {
    let xor = 0;
    while (index > 0) {
        xor ^= BIT[index];
        index -= index & -index;
    }
    return xor;
}

function xorRange(L, R) {
    // Build Fenwick Tree
    const BIT = new Array(R + 1).fill(0);
    for (let i = L; i <= R; i++) {
        updateBIT(BIT, i, i);
    }

    // Query Fenwick Tree
    const xorL = queryBIT(BIT, L - 1);
    const xorR = queryBIT(BIT, R);

    return xorL ^ xorR;
}

const L = 3;
const R = 6;
const result = xorRange(L, R);
console.log(`Bitwise XOR of all numbers from ${L} to ${R} is ${result}`);

Output:

Bitwise XOR of all numbers from 3 to 7 is 3

Time Complexity: O(NlogN) time, where N is the size of the range. Querying the Fenwick Tree takes O(logN) time.

Space Complexity: O(N) for storing the tree structure.

Bitwise Manipulation

In this approach, we directly manipulate bits to compute the XOR of numbers in the given range without using any additional data structures. This approach is based on observing patterns in the XOR operation.

Example: Consider an example where L=4 and R=8. We compute the XOR of all numbers from 4 to 8 by observing patterns in the XOR operation.

function xorRange(L, R) {
    let xorLR = 0;
    for (let i = L; i <= R; i++) {
        xorLR ^= i;
    }
    return xorLR;
}

const L = 4;
const R = 8;
const result = xorRange(L, R);
console.log(`Bitwise XOR of all numbers from ${L} to ${R} is ${result}`);

Output:

Bitwise XOR of all numbers from 4 to 8 is 8

Time Complexity: O(N), where N is the size of the range.

Space Complexity: O(1)

Article Tags :