Bit Manipulation · Bit Manipulation Fundamentals

Bitwise Basics

XOR, AND, OR, and shifts used to solve problems without extra space.

  • 7 min read
  • 17 practice questions
  • 4 graded problems
On this page
  1. Description
  2. The approach
  3. A second flavor: a bitmask as a set
  4. Where you'll see it
  5. Which tool for which job?
  6. Common mistakes
  7. Check yourself
  8. Key takeaways
  9. Quick revise
  10. Practice

Description

Every int is 32 bits, and some questions are easiest to answer at that level. Which number in this list appears only once? Is this number a power of two? Which of these 20 features are switched on? Each has an obvious answer with a hash set or a loop over values. Each also has a shorter answer that works on the bits directly, in O(1) extra space. This skill covers the core operations, XOR cancellation, bitmasks as sets, and the traps around negative numbers and shifts.

We'll go from simple to more technical:

  1. The pattern: AND, OR, XOR, shifts, and the tricks built from them (x & (x - 1), x & -x).
  2. A second flavor: an int as a set of up to 32 items.
  3. Where bits show up in production (flags, permissions, hashing, compact sets).
  4. What breaks it: negative numbers, shift distances, precedence, edge values.

The approach

Java

int singleNumber(int[] nums) {          // every value appears twice except one
    int result = 0;
    for (int num : nums) {
        result ^= num;                  // x ^ x == 0 and x ^ 0 == x
    }
    return result;
}

Python

def single_number(nums: list[int]) -> int:   # every value appears twice except one
    result = 0
    for num in nums:
        result ^= num                          # x ^ x == 0 and x ^ 0 == x
    return result

XOR is commutative and associative, so the order doesn't matter: every pair cancels to 0 wherever its two copies sit, and only the lone value survives. The same cancellation finds the missing number in 0..n (XOR all indices with all values) and swaps two variables without a temporary. It does not cancel a value that appears three times (x ^ x ^ x == x); that needs per-bit counting (below).

The other identities worth knowing cold:

Java

x & (x - 1)       // clears the lowest set bit:   12 (1100) -> 8 (1000)
x & -x            // keeps only the lowest set bit: 12 (1100) -> 4 (0100)
n > 0 && (n & (n - 1)) == 0      // n is a power of two (exactly one bit set)
(x >> i) & 1      // reads bit i

Python

x & (x - 1)                     # clears the lowest set bit:    12 (1100) -> 8 (1000)
x & -x                          # keeps only the lowest set bit: 12 (1100) -> 4 (0100)
n > 0 and (n & (n - 1)) == 0    # n is a power of two (exactly one bit set)
(x >> i) & 1                    # reads bit i

x & (x - 1) counts set bits in one step per 1 bit (Brian Kernighan's method). x & -x works because -x is ~x + 1 in two's complement: every bit above the lowest 1 is flipped, so only that bit survives the AND. With two lone values a and b among pairs, XOR-ing everything gives a ^ b; any 1 bit in it (say x & -x) is a bit where a and b differ, so splitting the numbers on that bit separates a from b.

n & 1 and n >> 1 equal n % 2 and n / 2 only for non-negative n: -7 % 2 is -1 (so n % 2 == 1 misses negative odd numbers) while -7 & 1 is 1, and -7 >> 1 is -4 (it rounds down) while -7 / 2 is -3 (it rounds toward zero).

A second flavor: a bitmask as a set

An int is a set of up to 32 small integers - bit i is 1 when i is in the set:

Java

mask | (1 << i)       // add i
mask & ~(1 << i)      // remove i (x ^ (1 << i) toggles it - it would add i if absent)
(mask & (1 << i)) != 0   // contains i? parentheses required
a | b, a & b, a & ~b  // union, intersection, difference - one instruction each
Integer.bitCount(mask)   // size

for (int mask = 0; mask < (1 << n); mask++) {    // every subset of n items (n <= 30)
    for (int i = 0; i < n; i++) {
        if (((mask >> i) & 1) == 1) { /* item i is in this subset */ }
    }
}

Python

mask | (1 << i)          # add i
mask & ~(1 << i)         # remove i (mask ^ (1 << i) toggles it - it would add i if absent)
(mask & (1 << i)) != 0   # contains i?
a | b, a & b, a & ~b     # union, intersection, difference
mask.bit_count()         # size (Python 3.10+)

for mask in range(1 << n):          # every subset of n items
    for i in range(n):
        if (mask >> i) & 1:
            pass                    # item i is in this subset

Subset enumeration visits 2^n masks - about a million for n = 20 - so it suits small n. When the question is about each bit position across many numbers, count per position instead: in "every value appears three times except one", each position's count of 1s is a multiple of 3 plus the lone value's bit, so count % 3 rebuilds the answer bit by bit.

Where you'll see it

Permission and feature flags packed into an int (flags | FLAG_X to set, flags & ~FLAG_X to clear, (flags & FLAG_X) != 0 to test); Unix file modes (chmod 755 is rwx = 4 + 2 + 1 for the owner, r-x = 4 + 1 for group and others); Java's EnumSet, which stores a set of up to 64 enum constants in a single long; BitSet and Bloom filters; IP subnet checks (address & netmask). Java's HashMap keeps a power-of-two table size so it can pick a bucket with hash & (size - 1) - which, unlike hash % size, is never negative for a negative hash code.

Which tool for which job?

You needUse
The one value appearing once (others twice)XOR everything
Others appear three timescount each bit position mod 3
Is n a power of two?n > 0 && (n & (n - 1)) == 0
The lowest set bitx & -x
A set of up to 32 or 64 small itemsan int or long bitmask
Every subset of every subsetsubmask enumeration, 3^n in total
The largest XOR of any subseta linear (XOR) basis
Bucket from a hash codeMath.floorMod(h, n)

Common mistakes

MistakeWhat happensDo this instead
n >>= 1 on a negative numberthe loop never ends (-1 >> 1 is -1)>>>, or n &= n - 1
1 << 32 in Javaequals 1, not 01L << i
flags & MASK != 0precedence surprise (C) or a compile error (Java)parenthesize
Power-of-two check without n > 00 and MIN_VALUE passtest n > 0
Math.abs(h) % n for a bucketa negative bucket when h is MIN_VALUEMath.floorMod(h, n)

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. Why does XOR-ing every element find the value that appears once among pairs - and why doesn't it work when the others appear three times?

Show answer

XOR is order-independent, x ^ x == 0 and x ^ 0 == x, so every pair cancels and the lone value remains. Three copies XOR to the value itself (x ^ x ^ x == x), so they don't cancel; count each bit position instead and take count % 3.

2. What does n & (n - 1) do, and why does the power-of-two test also need n > 0?

Show answer

It clears n's lowest 1 bit. A power of two has exactly one 1 bit, so the result is 0. But 0 has no bits to clear and Integer.MIN_VALUE (only the sign bit set) also gives 0, and neither is a power of two - hence n > 0.

3. while (n != 0) { count += n & 1; n >>= 1; } - what happens for n = -1, and what are two fixes?

Show answer

It never terminates: >> copies the sign bit in, so -1 stays -1. Use n >>>= 1 (zeros shift in, 32 iterations), or n &= n - 1 (one iteration per 1 bit - also 32 for -1). Or call Integer.bitCount(n).

Key takeaways

  • XOR cancels values that appear an even number of times, in any order - lone value, missing number, and (split on a differing bit) two lone values.
  • x & (x - 1) clears the lowest set bit; x & -x isolates it. Power-of-two tests need n > 0.
  • An int is a set of up to 32 small integers: | adds, & ~ removes, & tests, and masks 0 to 2^n - 1 enumerate subsets.
  • >> keeps the sign, >>> fills zeros; & 1 and >> 1 match % 2 and / 2 only for non-negative numbers.
  • Shift distances wrap (1 << 32 == 1), and ==/!= bind tighter than & - use 1L and parentheses.
  • When value tricks fail, count each bit position (sign bit included).

Quick revise

The whole skill on one page, for the night before an interview.

This page puts the lesson and the deep dive together. Skim it before practice or an interview, and go back to the full lesson for anything you don't recognize.

Pick the tool

You needUse
Lone value (pairs)XOR all
Lone value (triples)per-bit count mod 3
Power of twon > 0 && (n & (n - 1)) == 0
Small setsint/long bitmask
Subsets of subsetssub = (sub - 1) & mask
Max subset XORXOR basis
Hash bucketMath.floorMod

Snippets worth knowing by heart

Java

for (int sub = mask; ; sub = (sub - 1) & mask) {      // every submask, including 0
    // use sub
    if (sub == 0) break;
}
int bucket = Math.floorMod(key.hashCode(), buckets);  // never negative

Python

basis = [0] * 31                         # insert x into a XOR basis
for b in range(30, -1, -1):
    if not x >> b & 1:
        continue
    if not basis[b]:
        basis[b] = x
        break
    x ^= basis[b]

The traps

  • >> on negatives: -1 >> 1 is still -1, so the loop never ends. Use >>>, or n &= n - 1.
  • Shift distances: Java masks the distance, so 1 << 32 is 1. Use 1L << i for 64 bits.
  • Precedence: flags & MASK != 0 doesn't mean what it looks like. Parenthesize bit tests.
  • n > 0 in the power-of-two check: without it, 0 and MIN_VALUE pass. Test n > 0 first.
  • Math.abs(MIN_VALUE) stays negative, so a bucket index goes negative. Use Math.floorMod(h, n).

Staff-level points, one line each

  • "polygenelubricants".hashCode() is MIN_VALUE. Math.abs stays negative, so the bucket was -8; floorMod gives 2.
  • Held-Karp matched brute force on tours of up to 8 cities. 15 cities need 491,520 states instead of 87 billion orders.
  • Submasks of all masks: 3^n (59,049 for n = 10). Gosper's hack enumerates C(n, k) masks.
  • An XOR basis matched brute force; 100,000 numbers reduced to 30 vectors.
  • Python: ~5 is -6, -7 >> 1 is -4. Mask to 32 bits when porting.

Say it in an interview

  • "XOR cancels pairs, so the lone value is what's left."
  • "x & (x - 1) clears the lowest set bit, and x & -x isolates it."
  • "For small sets, the bitmask is the DP state."
  • "For buckets I use floorMod, because abs of MIN_VALUE is negative."

Practice

This skill comes with 17 multiple-choice questions that tell you which misconception a wrong answer reveals and 4 graded problems. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Bitwise Basics free

Counting Bits

MediumProCoding problemJava · Python

For every number i from 0 to n, count the 1s in its binary form. Return the counts as one array, in order.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Single Number II

MediumProCoding problemJava · Python

Every value in nums appears exactly three times except one, which appears once. Return that value, in O(n) time and O(1) extra space.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Two Single Numbers

MediumProCoding problemJava · Python

Every value in nums appears exactly twice except two different values, which appear once each. Return those two values (in either order), in O(n) time and O(1) extra space.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Practice Bitwise Basics free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime