Pattern 18 of 20

Bit Manipulation

Use XOR, masks and shifts to count, toggle and cancel out bits.

When to use it

  • Find the element that appears an odd number of times
  • Count set bits, or test and flip individual bits
  • Represent a small set as an integer mask

The idea

XOR cancels equal values, AND with a mask isolates bits, and n & (n − 1) clears the lowest set bit. These identities replace extra memory with a few integer operations.

Typical cost O(n) or O(number of bits) time, O(1) space.

How it works

Bit manipulation treats an integer as a row of switches. A handful of operations do most of the work: AND to test or clear bits, OR to set them, XOR to toggle, and shifts to move between positions. Each runs in constant time on the whole word.

XOR is the star. It is its own inverse (x ^ x = 0), and order does not matter, so XOR-ing a list where everything appears twice except one value leaves exactly that value. The same property finds a missing number when you XOR indices with values.

Two identities show up constantly: n & (n - 1) clears the lowest set bit, which lets you count set bits in as many steps as there are ones, and n & -n isolates the lowest set bit. A power of two is a positive n with n & (n - 1) equal to 0.

Bitmasks also encode small sets. With up to 20 items, every subset is an integer from 0 to 2^n - 1, which turns subset enumeration and DP over subsets into simple loops. In JavaScript remember that bitwise operators work on signed 32-bit integers.

How to attack it

  1. 1Look for pairs that cancel, parity, powers of two, or a small set that fits in a mask.
  2. 2Write down the identity you will rely on (x ^ x = 0, n & (n - 1), n & -n).
  3. 3Decide the word size and how negatives behave in your language.
  4. 4Loop over bits with shifts and masks rather than string conversions.
  5. 5Test with 0, 1, a negative value and the largest allowed value.

Template

A skeleton to adapt, not a solution to paste. Write it from memory a few times.

def single_number(nums):
    # Every value appears twice except one: pairs cancel under XOR.
    acc = 0
    for x in nums:
        acc ^= x
    return acc


def count_set_bits(n):
    count = 0
    while n:
        n &= n - 1       # clear the lowest set bit
        count += 1
    return count


def is_power_of_two(n):
    return n > 0 and n & (n - 1) == 0


def all_subsets(items):
    n = len(items)
    out = []
    for mask in range(1 << n):           # each mask is one subset
        out.append([items[i] for i in range(n) if mask >> i & 1])
    return out


def bit_ops(x, i):
    test = (x >> i) & 1
    set_bit = x | (1 << i)
    clear_bit = x & ~(1 << i)
    toggle = x ^ (1 << i)
    return test, set_bit, clear_bit, toggle

Variants

XOR cancellation
Find the single value, the missing number, or two unique values (split the list by any bit where they differ).
Counting bits
Clear the lowest bit repeatedly, or build counts for 0..n with dp[i] = dp[i >> 1] + (i & 1).
Bitmask subsets
Enumerate every subset of up to about 20 items, or run DP where the state is a set of visited items.
Bitwise addition
Sum without +: XOR gives the sum without carries, AND shifted left gives the carries; repeat until no carry.
Bit reversal and shifting
Build the result one bit at a time, shifting it left while shifting the input right.

Pitfalls

  • Operator precedence: in Python and JavaScript, == binds tighter than &, so wrap bitwise expressions in parentheses.
  • Using >> instead of >>> in JavaScript when you need an unsigned shift.
  • Infinite loops on negative numbers in Python, where integers have unbounded width; mask with & 0xFFFFFFFF.
  • Assuming 1 << 31 is positive in JavaScript (it is negative).
  • Using bitmasks for sets that are too large; 2^n blows up fast past about 20.

What it costs

OperationCost
AND, OR, XOR, shiftsO(1)
Count set bits with n & (n - 1)O(number of set bits)
XOR over a listO(n) time, O(1) space
Enumerate all subsetsO(n · 2^n)

25 Bit Manipulation problems

Easiest first. Problems marked Free can be solved without Pro.

  1. 1Lone Sensor ReadingFreeEasy
  2. 2Count the Lit SwitchesFreeEasy
  3. 3Bit Gap Between CodesFreeEasy
  4. 4Doubling Capacity CheckEasy
  5. 5Set-Bit Tally TableEasy
  6. 6Mirror a 32-Bit WordEasy
  7. 7Zigzag Binary PatternEasy
  8. 8Invert the Active BitsEasy
  9. 9Two Unpaired TicketsMedium
  10. 10Survivor of the TriplesMedium
  11. 11Adder Without ArithmeticMedium
  12. 12Shared Bits of a RangeMedium
  13. 13Every Feature-Flag ComboMedium
  14. 14Reflected Gray DialMedium
  15. 15Checksum Window QueriesMedium
  16. 16Fleet-Wide Bit DriftMedium
  17. 17No-Repeat Letter BannerMedium
  18. 18Disjoint Word-Pair ScoreMedium
  19. 19Balanced XOR SplitsMedium
  20. 20Nearest Code With Fixed OnesMedium
  21. 21Inspect Every RoomHard
  22. 22Cheapest Crew AssignmentHard
  23. 23Leanest Skill SquadHard
  24. 24Capped Semester PlannerHard
  25. 25Strongest XOR BlendHard

Solve them in the browser, in Python or JavaScript.