DSA Notes
Master bit manipulation completely — bitwise operators with truth tables, bit shifting, common tricks for setting/clearing/toggling bits, XOR magic properties, counting set bits (Brian Kernighan), power of two checks, swap without temp variable, and 15 classic interview problems solved with bit manipulation.
Introduction
Bit manipulation is the technique of directly working with individual binary digits (bits) of integers using bitwise operators. Instead of treating a number as a whole, you work at the level of its binary representation — the 0s and 1s stored in memory.
Why learn bit manipulation?
- Speed: Bitwise operations execute in a single CPU clock cycle — faster than any arithmetic operation
- Space: Pack multiple boolean flags into a single integer (32 booleans in one 32-bit int)
- Elegance: Many problems have beautifully short solutions using bit tricks
- Interviews: Google, Amazon, Microsoft frequently ask bit manipulation problems
The Six Bitwise Operators
1. AND (&) — Both must be 1
print(5 & 3) # 1 (0101 & 0011 = 0001)
print(12 & 10) # 8 (1100 & 1010 = 1000)Common uses: Check if a bit is set, clear a bit, check if number is even/odd.
2. OR (|) — At least one must be 1
print(5 | 3) # 7 (0101 | 0011 = 0111)
print(12 | 10) # 14 (1100 | 1010 = 1110)Common uses: Set a specific bit to 1.
3. XOR (^) — Exactly one must be 1 (exclusive or)
print(5 ^ 3) # 6 (0101 ^ 0011 = 0110)
print(5 ^ 5) # 0 (anything XOR itself = 0)
print(5 ^ 0) # 5 (anything XOR 0 = itself)XOR Magic Properties:
Common uses: Find unique element, swap without temp, toggle bits, cryptography.
4. NOT (~) — Flip all bits
print(~5) # -6 (~n = -(n+1))
print(~0) # -1
print(~-1) # 0Rule: ~n = -(n + 1) always.
5. Left Shift (<<) — Multiply by 2
print(5 << 1) # 10 (5 × 2)
print(5 << 2) # 20 (5 × 4)
print(5 << 3) # 40 (5 × 8)
print(1 << 4) # 16 (2⁴)Rule: n << k = n × 2^k
6. Right Shift (>>) — Divide by 2
print(10 >> 1) # 5 (10 // 2)
print(20 >> 2) # 5 (20 // 4)
print(7 >> 1) # 3 (7 // 2, floor)Rule: n >> k = n // 2^k (floor division)
Essential Bit Tricks
Check if nth bit is set
def is_bit_set(num, n):
"""Return True if nth bit (0-indexed from right) is 1."""
return bool(num & (1 << n))
print(is_bit_set(13, 0)) # True (13=1101, bit 0 = 1)
print(is_bit_set(13, 1)) # False (13=1101, bit 1 = 0)
print(is_bit_set(13, 2)) # True (13=1101, bit 2 = 1)
print(is_bit_set(13, 3)) # True (13=1101, bit 3 = 1)Set nth bit to 1
def set_bit(num, n):
"""Set nth bit to 1."""
return num | (1 << n)
print(set_bit(10, 0)) # 11 (1010 | 0001 = 1011)
print(set_bit(10, 2)) # 14 (1010 | 0100 = 1110)Clear nth bit (set to 0)
def clear_bit(num, n):
"""Set nth bit to 0."""
return num & ~(1 << n)
print(clear_bit(13, 2)) # 9 (1101 & ~0100 = 1101 & 1011 = 1001)
print(clear_bit(13, 0)) # 12 (1101 & ~0001 = 1101 & 1110 = 1100)Toggle nth bit
def toggle_bit(num, n):
"""Flip nth bit — 0 becomes 1, 1 becomes 0."""
return num ^ (1 << n)
print(toggle_bit(13, 1)) # 15 (1101 ^ 0010 = 1111)
print(toggle_bit(13, 0)) # 12 (1101 ^ 0001 = 1100)Check if number is odd or even
def is_odd(n):
return bool(n & 1) # Last bit is 1 for odd numbers
print(is_odd(7)) # True
print(is_odd(8)) # FalseSwap two numbers without a temporary variable
def swap_xor(a, b):
"""XOR swap — no temp variable needed."""
a = a ^ b # a now holds a XOR b
b = a ^ b # b = (a XOR b) XOR b = a
a = a ^ b # a = (a XOR b) XOR a = b
return a, b
print(swap_xor(5, 3)) # (3, 5)Counting Set Bits
Naive Method — O(log n)
def count_bits_naive(n):
count = 0
while n:
count += n & 1 # Check last bit
n >>= 1 # Shift right
return count
print(count_bits_naive(13)) # 3 (1101 has three 1s)Brian Kernighan's Algorithm — O(number of set bits)
Key insight: n & (n-1) removes the rightmost set bit.
def count_bits_kernighan(n):
"""
Each iteration removes one set bit.
Loops only as many times as there are set bits.
"""
count = 0
while n:
n = n & (n - 1) # Remove rightmost set bit
count += 1
return count
# Trace for n=12 (1100):
# n=12 (1100): 12 & 11 = 1100 & 1011 = 1000 = 8, count=1
# n=8 (1000): 8 & 7 = 1000 & 0111 = 0000 = 0, count=2
# n=0: stop. Result = 2 ✓
print(count_bits_kernighan(12)) # 2
print(count_bits_kernighan(255)) # 8 (11111111)Python Built-in
print(bin(13).count('1')) # 3
print(13.bit_count()) # 3 (Python 3.10+)Power of Two Check
A power of two has exactly one bit set: 1, 10, 100, 1000...
def is_power_of_two(n):
"""
n & (n-1) removes the lowest set bit.
If n is a power of two, only one bit is set.
After removing it, n becomes 0.
"""
return n > 0 and (n & (n - 1)) == 0
print(is_power_of_two(16)) # True (10000)
print(is_power_of_two(12)) # False (1100, has 2 bits set)
print(is_power_of_two(0)) # False
print(is_power_of_two(1)) # True (2^0)XOR Classic Problems
Find the Single Non-Duplicate
Find Two Non-Duplicate Elements
Bitmask for Subsets
Important Bit Tricks Reference
# Remove lowest set bit
n & (n - 1)
# Isolate lowest set bit
n & (-n)
# Check if nth bit is set
n & (1 << pos)
# Set nth bit
n | (1 << pos)
# Clear nth bit
n & ~(1 << pos)
# Toggle nth bit
n ^ (1 << pos)
# Get value of lowest set bit
n & (-n)
# Clear all bits from bit 0 to pos
n & ~((1 << (pos + 1)) - 1)
# Multiply by 2^k
n << k
# Divide by 2^k (floor)
n >> k
# Check even
not (n & 1)
# Get absolute value without branch
mask = n >> 31 # All 0s for positive, all 1s for negative
(n + mask) ^ maskInterview Problems
Problem 1 — Reverse Bits of a 32-bit Integer
def reverse_bits(n):
result = 0
for _ in range(32):
result = (result << 1) | (n & 1)
n >>= 1
return result
print(reverse_bits(0b00000010100101000001111010011100))
# 0b00111001011110000010100101000000Problem 2 — Number of Bits to Flip to Convert A to B
def count_flips(a, b):
"""Count bits that differ between a and b."""
diff = a ^ b # Bits that are different
count = 0
while diff:
diff = diff & (diff - 1) # Clear lowest set bit
count += 1
return count
print(count_flips(29, 15)) # 2 (29=11101, 15=01111, differ at 2 bits)Problem 3 — Sum of Two Integers Without + Operator
def get_sum(a, b):
"""
Use bit operations to add two numbers.
carry = a AND b (bits that generate carry)
sum = a XOR b (bits without carry)
Repeat until no carry.
"""
mask = 0xFFFFFFFF # 32-bit mask
while b & mask:
carry = (a & b) << 1
a = a ^ b
b = carry
return a if b == 0 else a & mask
print(get_sum(1, 2)) # 3
print(get_sum(-1, 1)) # 0Summary
| Operation | Code | Use Case | |
|---|---|---|---|
| Check bit n | n & (1 << pos) | Is this bit set? | |
| Set bit n | `n \ | (1 << pos)` | Force bit to 1 |
| Clear bit n | n & ~(1 << pos) | Force bit to 0 | |
| Toggle bit n | n ^ (1 << pos) | Flip a bit | |
| Is even | n & 1 == 0 | Parity check | |
| Is power of 2 | n & (n-1) == 0 | Power check | |
| Remove lowest bit | n & (n-1) | Count set bits | |
| Isolate lowest bit | n & (-n) | Find rightmost 1 | |
| Left shift k | n << k | Multiply by 2^k | |
| Right shift k | n >> k | Divide by 2^k |
Bit manipulation turns complex problems into elegant one-liners. The more you practice, the more naturally these patterns appear in algorithm design.
*Next: Trie Data Structure*
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Bit Manipulation — Complete Guide with All Tricks and Interview Problems.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Data Structures & Algorithms topic.
Search Terms
data-structures-algorithms, data structures & algorithms, data, structures, algorithms, advanced, topics, bit
Related Data Structures & Algorithms Topics