Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Coding Interview Patterns  Module 19 – Tries

Binary tries for maximum XOR

Find the largest XOR of two numbers in an array with a binary trie, one greedy walk of 30 bits per number, then answer XOR queries under a limit.

  • Advanced
  • 40 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, quickjs 0.32.0, Java 25, Clang 21.0.0 and Go 1.27.1
  • By MySmartCoPilot
Free intro, Pro: 7 of 40 minutes free
Free: The problem: the most different pair of device IDs · The brute force, and why it fails at these sizes · What to notice. With a pass: the other 12 sections and 3 interview answers, about 33 minutes.

What you will learn

  • Build a binary trie that stores integers bit by bit, the most significant bit first
  • Find the maximum XOR of two numbers of an array in O(n × b) with a greedy walk
  • Prove that taking the opposite bit at every level gives the largest XOR
  • Answer XOR queries with a value limit, offline by sorting and online with subtree minimums
  • Apply the trie to XORs of subarrays, the smallest XOR of a pair and counting pairs below a bound

Before you start

What you’ll learn · Before you start

What you will learn

  • Build a binary trie that stores integers bit by bit, the most significant bit first
  • Find the maximum XOR of two numbers of an array in O(n × b) with a greedy walk
  • Prove that taking the opposite bit at every level gives the largest XOR
  • Answer XOR queries with a value limit, offline by sorting and online with subtree minimums
  • Apply the trie to XORs of subarrays, the smallest XOR of a pair and counting pairs below a bound

Before you start

On this page

A binary trie stores integers as paths of bits, the most significant bit first, so two numbers share a path for as long as their leading bits agree. It solves the maximum XOR of two numbers in an array in O(n × b) time for b-bit numbers: insert the numbers, and for each one walk down the trie, taking the opposite bit at every level where that child exists. The greedy choice works because a 1 in a higher bit of a XOR is worth more than all the lower bits together. For 30-bit numbers that is 30 steps per number, where checking every pair costs up to n − 1 XORs per number.

The problem: the most different pair of device IDs

The problem

A sensor network gives each of its devices a 30-bit ID. To test how its radios detect errors, an engineer wants the two devices whose IDs differ most in the binary sense: the pair whose XOR is largest. Write max_xor(ids), which returns the largest a ^ b over two devices at different positions of the list. Limits: 2 ≤ n ≤ 200,000 and 0 ≤ ID < 2³⁰; IDs may repeat.

  • [41, 18, 7, 33, 60, 12] gives 59, from 41 and 18: 101001 XOR 010010 = 111011.
  • [5, 9, 12, 3] gives 15, from 12 and 3: 1100 XOR 0011 = 1111, the largest four-bit value.
  • [7, 7] gives 0: two devices with the same ID differ nowhere.
The four-bit binary trie of 3, 5, 9 and 12. The walk for 12 = 1100 takes the opposite bit at every level and ends at 0011 = 3.01010110001110root01000110110010101001100011= 30101= 51001= 91100= 12Query 12 = 1100 wants 0, 0, 1 and 1,finds all four, and reaches 0011 = 3:1100 XOR 0011 = 1111 = 15.

At every level the walk takes the opposite bit when that child exists

Text description of the diagram

The diagram is a binary trie of the numbers 3, 5, 9 and 12, written with four bits each: 0011, 0101, 1001 and 1100. Each box is a node labelled with the bits on its path from the root, and each line is labelled with the bit it adds, 0 or 1.

  1. The root has two children: 0, the start of 0011 and 0101, and 1, the start of 1001 and 1100.
  2. Below 0 are 00 and 01; below 1 are 10 and 11. Each of these four has one child, and each of those one leaf: 001 then 0011 = 3, 010 then 0101 = 5, 100 then 1001 = 9, and 110 then 1100 = 12.
  3. The walk for the query 12 = 1100 is drawn with thick lines and shaded boxes. Its first bit is 1, so it wants the child 0, which exists. Its second bit is 1, so it wants 0 again, and 00 exists. Its third and fourth bits are 0, so it wants 1 twice, and 001 and 0011 exist.

Every bit the walk wanted was there, so all four bits of the XOR are 1: 1100 XOR 0011 = 1111 = 15, the largest XOR of 12 with any of the four numbers.

The brute force, and why it fails at these sizes

XOR every pair and keep the largest:

The brute force: the XOR of every pair, with the best pair in binary Python · brute/brute.py
"""The brute force for the most different pair of device IDs: the XOR of every pair."""


def max_xor_brute(ids):
    """The largest a ^ b over pairs of different positions, the pair itself, and how many pairs were tried."""
    best, pair, tried = -1, None, 0
    for i in range(len(ids)):
        for j in range(i + 1, len(ids)):
            tried += 1
            if ids[i] ^ ids[j] > best:
                best, pair = ids[i] ^ ids[j], (ids[i], ids[j])
    return best, pair, tried


if __name__ == "__main__":
    for ids in ([41, 18, 7, 33, 60, 12], [5, 9, 12, 3], [7, 7]):
        best, (a, b), tried = max_xor_brute(ids)
        width = max(a, b, 1).bit_length()
        print(f"{ids}")
        print(f"  {a} ^ {b} = {best}: {a:0{width}b} ^ {b:0{width}b} = {best:0{width}b}, {tried} pair{'s' * (tried != 1)} tried")
    n = 200_000
    print()
    print(f"At the limits: {n:,} IDs make {n * (n - 1) // 2:,} pairs")

Output

[41, 18, 7, 33, 60, 12]
  41 ^ 18 = 59: 101001 ^ 010010 = 111011, 15 pairs tried
[5, 9, 12, 3]
  12 ^ 3 = 15: 1100 ^ 0011 = 1111, 6 pairs tried
[7, 7]
  7 ^ 7 = 0: 111 ^ 111 = 000, 1 pair tried

At the limits: 200,000 IDs make 19,999,900,000 pairs

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 brute.py

It is O(n²): n(n − 1)/2 = 19,999,900,000 pairs at n = 200,000. At the 10⁸ simple steps a second that the constraints lesson plans with, compiled code needs more than three minutes, and Python far longer.

What to notice

A XOR is large when its high bits are 1, and the top bit decides on its own: bit 29 is worth 2²⁹, more than 2²⁹ − 1, the sum of all the bits below it. So the best partner for a number differs from it as early as possible: first a partner whose top bit differs, then, among those, one whose next bit differs too, and so on. Numbers that share their top bits share a path in a binary trie, so each of those questions is a single step down it.

The trie and the greedy walk, step by step Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • Why the opposite bit is always the right choice
  • A dry run on 12 and on 5
  • The code in five languages
  • Speed and memory, measured
  • Queries with a value limit, offline and online
  • Variants: subarrays, the smallest XOR and pairs below a bound
  • Edge cases and common bugs
  • Exercise
    • The largest XOR with a number under a limit
  • A practice set with sample answers
  • Check yourself
  • Interview questions
    • Why does the walk for the largest XOR take the opposite bit at the top level even when that branch has poor lower bits?
    • Queries (x, m) arrive one at a time and must be answered at once: the largest x ^ y over stored y with y ≤ m, or −1. Numbers may also be added between queries. Sorting the queries is impossible. How do you answer each one in O(bits), and why is your walk never stuck?
    • Given n ≤ 2 × 10⁵ values below 2³⁰, find the largest XOR of a run of consecutive values. Explain why checking every run is too slow, how prefix XORs turn the question into a pair question, and what the trie then costs.
    • A service keeps a binary trie of up to 10 million 32-bit numbers to answer largest-XOR queries, and may use 256 MB. Estimate the trie's nodes and bytes, decide whether it fits, and describe what you would change if it does not.
  • Key takeaways

7 runnable examples (Build and run all three, C++, Go, Java, JavaScript, Python) · 1 exercise with sample tests · 3 interview answers · about 27 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.