Bit Manipulation

Mediumbits · xor · math · binary · bitmask⏱ 5 min readUpdated

Treat integers as rows of 32 switches and use XOR, AND, OR and shifts to cancel duplicates, count bits, encode sets and do arithmetic in O(1) space.

PatternBit Manipulation

Instinct Pairs that cancel, counting 1s, powers of two, subsets as numbers, or 'no + or - allowed' - drop to binary and use XOR, AND, OR and shifts.

Memory hack XOR is a forgetful twin detector - see something twice and it vanishes; n & (n-1) snips off the last lit bulb.

At a glance

When to use it

  • Every value appears twice except one, or one number is missing from 0..n
  • You need to count set bits, test a power of two or reverse bits
  • Arithmetic operators are banned (add without + or -)
  • n is small (about 20 or less) and every subset can be a bitmask

Key idea

Treat each integer as 32 switches and use XOR to cancel pairs, n & (n-1) to drop the lowest set bit and shifts to move bits, turning hash-set or loop-heavy solutions into O(n) time with O(1) extra space.

Typical complexity

O(n) time, O(1) space

How to spot it If the problem says "appears twice except one", "no extra space" or "without + and -" and asks for a lone value, a bit count or a sum, think bit manipulation first.

The instinct

Every int is secretly an array of 32 booleans that the CPU can flip, combine and slide in a single instruction. Bit manipulation problems reward you for noticing that the question is really about parity, presence, or binary structure rather than about magnitude. If a hash set would work but the interviewer asks for O(1) extra space, or the problem says "without using + or -", the answer is almost always hiding in the bits.

Recognise it

Signal in the problem Why it points here
"every element appears twice except one" x ^ x = 0 and x ^ 0 = x, so XOR of everything leaves the loner.
"number of 1 bits / Hamming weight / Hamming distance" n & (n - 1) clears the lowest set bit; count how many times you can do it.
"is it a power of two / power of four" A power of two has exactly one set bit.
"add two integers without + or -" XOR is sum-without-carry, AND shifted left is the carry.
"missing number in 0..n" XOR indices with values; every present number cancels.
"reverse bits / unsigned 32-bit integer" Shift bits out of one end and into the other, 32 times.
"AND of all numbers in a range" The answer is the common binary prefix of the endpoints.
"n is at most 16-20, try every subset" A mask from 0 to 2^n - 1 enumerates subsets.

Not this pattern if...

  • Duplicates can appear an arbitrary number of times and you need counts - use a hash map or counting array.
  • Values are huge (beyond 64 bits) or the question is really about decimal digits - use math or strings.
  • "Subsets" have n around 40+ - 2^n masks are too many; think backtracking with pruning or meet-in-the-middle.

Memory hack

Tip

"XOR is a forgetful twin detector; n & (n-1) snips the last lit bulb." XOR remembers only what it has seen an odd number of times. n & (n - 1) turns off the rightmost 1, while n & -n keeps only that rightmost 1.

Analogy: a row of light switches in a hallway. AND asks "are both lights on?", OR asks "is either on?", XOR asks "are they different?", and a shift slides every switch one door over. Flipping a switch twice leaves the hallway as it was - that is why paired numbers cancel.

Say it out loud in the interview:

  1. "What property survives in binary - parity, a single set bit, or a shared prefix?"
  2. "Which identity do I need: x ^ x = 0, n & (n-1), n & -n, or (n >> i) & 1?"
  3. "Am I safe on negatives and overflow - should I use >>> and a long?"

How it works

The toolbox is small - learn these six moves and most problems become a two-line loop:

Goal Expression
Read bit i (n >> i) & 1
Set / clear / toggle bit i n | (1 << i), n & ~(1 << i), n ^ (1 << i)
Drop lowest set bit n & (n - 1)
Isolate lowest set bit n & -n
Bits in 0..n via DP bits[i] = bits[i >> 1] + (i & 1)
Add without + sum = a ^ b, carry = (a & b) << 1, repeat until carry is 0

Worked trace for Sum of Two Integers, a = 5 (0101), b = 3 (0011):

Step a (partial sum) b (carry)
start 0101 0011
1 0110 (5 ^ 3) 0010 ((5 & 3) << 1)
2 0100 0100
3 0000 1000
4 1000 = 8 0000 -> stop

For Single Number III (two loners), XOR everything to get x ^ y, isolate any set bit with d & -d - x and y differ there - then split the array into two groups by that bit and XOR each group separately.

Java template

java
class BitTricks {
    // XOR fold: whatever appears an odd number of times survives.
    static int xorAll(int[] nums) {
        int acc = 0;
        for (int x : nums) acc ^= x;
        return acc;
    }

    // Kernighan: loop runs once per set bit, works for negatives too.
    static int popCount(int n) {
        int count = 0;
        while (n != 0) {
            n &= n - 1;
            count++;
        }
        return count;
    }

    // Walk all 32 positions; use >>> so the sign bit does not smear.
    static int reverseBits(int n) {
        int result = 0;
        for (int i = 0; i < 32; i++) {
            result = (result << 1) | (n & 1);
            n >>>= 1;
        }
        return result;
    }

    // Arithmetic without + : XOR is the sum, AND<<1 is the carry.
    static int add(int a, int b) {
        while (b != 0) {
            int carry = (a & b) << 1;
            a ^= b;
            b = carry;
        }
        return a;
    }

    // Subset enumeration: each mask is one subset of n items.
    static void forEachSubset(int n) {
        for (int mask = 0; mask < (1 << n); mask++) {
            for (int i = 0; i < n; i++) {
                if (((mask >> i) & 1) == 1) {
                    // item i is in this subset - problem-specific work here
                }
            }
        }
    }
}

Complexity

Operation Time Space
XOR fold over the array O(n) O(1)
Pop count (Kernighan) O(set bits) <= O(32) O(1)
Reverse bits / scan all bits O(32) = O(1) O(1)
Counting Bits for 0..n O(n) O(n) output
Subset enumeration O(2^n · n) O(1) besides output

Variations

  • Cancellation by XOR - pairs vanish: Single Number, Missing Number.
  • Partition by a differing bit - find the bit where two answers differ, then split: Single Number III.
  • Per-bit counting - count each of the 32 bits modulo k when elements repeat k times (Single Number II).
  • Bit DP - reuse the answer for i >> 1 or i & (i - 1): Counting Bits.
  • Common prefix - shift both ends right until equal, then shift back: Bitwise AND of Numbers Range.
  • Carry simulation - XOR plus shifted AND: Sum of Two Integers.
  • Bitmask as a set - visited states in BFS or DP over subsets (e.g. travelling-salesman-style DP).

Common mistakes

Warning

Java has no unsigned int. Using >> on a negative number copies the sign bit forever, so a "while (n != 0) n >>= 1" loop never ends. Use >>> for logical shifts, or loop a fixed 32 times.

  • Operator precedence: n & 1 == 0 parses as n & (1 == 0) and does not compile in Java - always parenthesise (n & 1) == 0.
  • Writing 1 << 31 or 1 << 32 and expecting a positive or 64-bit result; use 1L << k for longs.
  • Treating n & (n - 1) == 0 as "power of two" without also checking n > 0 (0 and Integer.MIN_VALUE slip through).
  • Forgetting that ~x equals -x - 1, so ~ is not "negative x".
  • Reaching for bit tricks when a plain hash set is clearer and space is not constrained - mention both and let the interviewer choose.

All practice problems

8 problems on this site use this pattern, easiest first. Solve them in order and say the instinct out loud before you code.

My notes saved in this browser