LeetCode #89 Medium

Gray Code

Gray Code is LeetCode 89 (Medium). Return any n-bit gray code sequence: a permutation of all 2ⁿ integers in [0, 2ⁿ − 1] where every consecutive pair, and the last and first pair, differ in exactly one bit.

With n up to 16 the output can hold 65,536 values, so the sequence has to be produced directly rather than searched for.

Constraints
  • 1 <= n <= 16
mathbit-manipulationbacktracking
Open on LeetCode ↗
02

Intuition

Searching for a valid ordering — pick a value, then hunt for an unused one a single bit away — is backtracking over an exponential space, and it is unnecessary. There is a gray code formula.

The i-th gray code is i XOR (i >> 1). It works because i and i + 1 differ in a trailing run of bits: the lowest zero flips to one and every one below it flips to zero. XOR-ing each value with itself shifted right cancels all of those flips except one, so consecutive outputs always differ in a single bit.

The wraparound comes free: the last value differs from the first only in the top bit.

How to spot this pattern

A closed form beats a search whenever the output is a complete enumeration with a structural rule. The tell here is that any valid sequence is accepted and every value must appear exactly once — that is a permutation to construct, not a space to explore.

03

Approach

Try it first

Before reading on: write out the 3-bit sequence 0, 1, 3, 2, 6, 7, 5, 4 next to the plain binary counts 0..7 and compare them bit by bit. The relationship between the two columns is the entire solution. Aim for O(2ⁿ) with no recursion.

1

Produce the sequence instead of searching for it

There are 2ⁿ values to emit, and any valid n-bit gray code sequence is accepted. A closed form gives the i-th value directly, so a single loop from 0 to 2ⁿ − 1 builds the whole answer with no recursion, no backtracking and no bookkeeping of which values are still unused.

2

Apply i XOR (i >> 1)

For each i, append i ^ (i >> 1). Two details decide whether it works:

  • Shift right, not left: a left shift produces values outside the n-bit range and destroys the single-bit property.
  • Keep the parentheses: ^ binds looser than >> in some languages but not all, so spell the order out.
3

Count 2ⁿ values, not n

The loop bound is 1 << n, the number of n-bit values. Using n itself returns a truncated prefix that happens to look plausible for small inputs, which is why this bug survives a quick test.

04

Gray Code solution in Python | C++ | Java

▶1class Solution:
▶2 def grayCode(self, n: int) -> list[int]:
▶3 total = 1 << n
▶4 result = []
▶5 for i in range(total):
▶6 result.append(i ^ (i >> 1))
▶7 return result
ibitsvalueempty4 values to produce
n24 codes to produce
resultemptyfilled in index order
Start. Hunting for a next value one bit away from the last is backtracking over an exponential space. The i-th gray code has a closed form, i ^ (i >> 1), so each value can be written down from its index alone.
ibitsvalue00000 → 0
i0index
i >> 10shifted right one place
i ^ (i >> 1)000
At i = 0 the expression gives 0, so the sequence starts at zero. Every later value is computed the same way, with no reference to this one.
ibitsvalue000010111 → 1, bit 0 flipped
i1index
i >> 10shifted right one place
i ^ (i >> 1)101
1 ^ 0 = 1. Exactly one bit differs from the previous value — bit 0 — which is what XOR-ing with the shifted copy guarantees, not a coincidence of this input.
ibitsvalue0000101121132 → 3, bit 1 flipped
i2index
i >> 11shifted right one place
i ^ (i >> 1)311
2 ^ 1 = 3. Exactly one bit differs from the previous value — bit 1 — which is what XOR-ing with the shifted copy guarantees, not a coincidence of this input.
ibitsvalue00001011211331023 → 2, bit 0 flipped
i3index
i >> 11shifted right one place
i ^ (i >> 1)210
3 ^ 1 = 2. Exactly one bit differs from the previous value — bit 0 — which is what XOR-ing with the shifted copy guarantees, not a coincidence of this input.
ibitsvalue0000101121133102wrapanswer [0, 1, 3, 2]
answer[0, 1, 3, 2]4 values, each once
Done. Every consecutive pair differs in one bit, and so do the last and first — here 2 and 0 differ only in the top bit. That wraparound is part of the requirement and easy to miss when checking by hand.
05

Reflect and prefix

Start from [0] and grow one bit at a time. For each new bit, append the list so far in reverse order with that bit set. Reversing is what keeps the seam valid: the two values meeting at the mirror point are identical except for the bit just added.

▶1class Solution:
▶2 def grayCode(self, n: int) -> list[int]:
▶3 result = [0]
▶4 for i in range(n):
▶5 high = 1 << i
▶6 for j in range(len(result) - 1, -1, -1):
▶7 result.append(result[j] | high)
▶8 return result
06

Common pitfalls

Building it by mirroring the previous sequence

✗ Wrong
res = [0]
for i in range(n):
    res += [x | (1 << i) for x in reversed(res)]
✓ Right
for i in range(total):
    result.append(i ^ (i >> 1))

The mirroring construction is correct and shows where gray code comes from, but it repeatedly reverses and reallocates the list it is building. The formula computes each entry independently in O(1), with no dependence on the entries before it.

Shifting the wrong way

✗ Wrong
result.append(i ^ (i << 1))
✓ Right
result.append(i ^ (i >> 1))

Left-shifting produces values outside the n-bit range and breaks the single-bit-change property. The identity requires XOR with the value shifted right by one.

Computing the wrong sequence length

✗ Wrong
total = n
✓ Right
total = 1 << n

A Gray code of n bits enumerates all 2^n values, not n of them. 1 << n is the count; using n returns a truncated prefix.

07

Edge cases

n = 1

The loop runs twice and returns [0, 1], the smallest real sequence: one bit toggling, and the wraparound back to 0 also flips that one bit.

The wraparound pair

The last value and the first differ only in the top bit, which the formula guarantees. It is easy to forget when checking your own output by hand.

n = 16, the largest input

65,536 values, each one constant-time expression, so the formula scales without any extra bookkeeping.

08

Complexity

Time
O(2^n)
Space
O(2^n)
must produce all 2^n codes; each is O(1) to compute