🧮 Bit Manipulation
Working directly with the binary representation of numbers. Often turns problems requiring extra space or loops into O(1) constant-time operations using clever bit tricks.
The Core Bitwise Operators (Recap)
5 & 3 # 1 AND: bit is 1 only if BOTH bits are 1
5 | 3 # 7 OR: bit is 1 if EITHER bit is 1
5 ^ 3 # 6 XOR: bit is 1 if bits DIFFER
~5 # -6 NOT: inverts every bit
5 << 1 # 10 left shift: multiply by 2 per shift
5 >> 1 # 2 right shift: divide by 2 per shift (floor)See the core Python folder’s Operators note for the base syntax.
Checking, Setting, and Clearing Bits
def get_bit(num, i):
return (num >> i) & 1 # shift the target bit to position 0, mask everything else off
def set_bit(num, i):
return num | (1 << i) # OR with a mask that has only bit i set
def clear_bit(num, i):
return num & ~(1 << i) # AND with a mask that has every bit set EXCEPT bit i
def toggle_bit(num, i):
return num ^ (1 << i) # XOR flips exactly the target bit
get_bit(5, 0) # 1, since 5 is 101 in binary
set_bit(5, 1) # 7, sets bit 1: 101 -> 111
clear_bit(5, 0) # 4, clears bit 0: 101 -> 100Counting Set Bits
def count_bits(n):
count = 0
while n:
count += n & 1
n >>= 1
return count
bin(13) # '0b1101'
count_bits(13) # 3
bin(13).count("1") # 3, simpler built-in approach for everyday useBrian Kernighan’s Trick (Faster: Skips Straight to Each Set Bit)
def count_bits_fast(n):
count = 0
while n:
n &= (n - 1) # clears the LOWEST set bit each iteration
count += 1
return countWhy
n & (n - 1)clears the lowest set bitSubtracting 1 flips all bits from the lowest set bit downward. ANDing with the original number keeps everything above that bit unchanged while zeroing out that lowest set bit and everything below it. This makes the loop run only as many times as there are SET bits, not the total bit width.
XOR Tricks
5 ^ 5 # 0, a number XORed with itself is always 0
5 ^ 0 # 5, a number XORed with 0 is unchangedFinding the Single Number Among Duplicates
def single_number(nums):
result = 0
for num in nums:
result ^= num # every PAIR of duplicates cancels out to 0, leaving only the unpaired value
return result
single_number([4, 1, 2, 1, 2]) # 4O(n) time, O(1) space, dramatically simpler than the equivalent hash-set-counting approach.
Swapping Without a Temp Variable
a, b = 5, 3
a ^= b
b ^= a
a ^= b
# a=3, b=5, no temp variable needed (though Python's a, b = b, a is simpler and preferred in practice)Checking If a Number Is a Power of 2
def is_power_of_two(n):
return n > 0 and (n & (n - 1)) == 0
is_power_of_two(16) # True, 16 is 10000, 15 is 01111, AND is 0
is_power_of_two(18) # FalseWhy this works
A power of 2 has EXACTLY one set bit. Subtracting 1 flips that bit off and every bit below it on. ANDing the two together always yields 0 for a true power of 2, and something nonzero otherwise.
Reversing Bits
def reverse_bits(n, bit_length=32):
result = 0
for i in range(bit_length):
bit = (n >> i) & 1
result |= (bit << (bit_length - 1 - i))
return resultBitmasking for Subsets
Any subset of a set of n elements can be represented as an n-bit number, where bit i indicates whether element i is included. This gives a clean way to iterate over ALL 2ⁿ subsets.
def all_subsets(nums):
n = len(nums)
subsets = []
for mask in range(1 << n): # 1 << n = 2^n, all possible bitmasks
subset = [nums[i] for i in range(n) if mask & (1 << i)]
subsets.append(subset)
return subsets
all_subsets([1, 2, 3])
# [[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]]Bitmask DP
This same idea extends into “bitmask dynamic programming,” used for problems like the Traveling Salesman Problem on small inputs, where
dp[mask][i]represents the best result having visited exactly the set of nodes inmask, ending at nodei.
Recognizing Bit Manipulation Problems
Signals to watch for
- Anything involving powers of 2, binary representations, or “using O(1) extra space.”
- Finding a unique/missing/duplicate number among otherwise-paired values (XOR tricks).
- Small input sizes (
n <= 20or so) hinting at a bitmask-based subset enumeration or DP.- Explicit mentions of AND/OR/XOR/shift operations in the problem statement itself.